@@ -14,3 +14,6 @@ dotnet_diagnostic.CS8629.severity = silent
|
||||
|
||||
# CS8602: Dereference of a possibly null reference.
|
||||
dotnet_diagnostic.CS8602.severity = silent
|
||||
|
||||
# CS8620: Argument cannot be used for parameter due to differences in the nullability of reference types.
|
||||
dotnet_diagnostic.CS8620.severity = silent
|
||||
|
||||
Generated
+9
-7
@@ -23,11 +23,13 @@
|
||||
"react-router": "^6.3.0",
|
||||
"react-router-dom": "^6.3.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"terser": ">=5.14.2",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint-config-react-app": "^7.0.1",
|
||||
"jest-editor-support": "^30.1.0"
|
||||
"jest-editor-support": "^30.1.0",
|
||||
"terser": ">=5.14.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
@@ -15455,9 +15457,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.14.1",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.14.1.tgz",
|
||||
"integrity": "sha512-+ahUAE+iheqBTDxXhTisdA8hgvbEG1hHOQ9xmNjeUJSoi6DU/gMrKNcfZjHkyY6Alnuyc+ikYJaxxfHkT3+WuQ==",
|
||||
"version": "5.14.2",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz",
|
||||
"integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==",
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.2",
|
||||
"acorn": "^8.5.0",
|
||||
@@ -27758,9 +27760,9 @@
|
||||
}
|
||||
},
|
||||
"terser": {
|
||||
"version": "5.14.1",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.14.1.tgz",
|
||||
"integrity": "sha512-+ahUAE+iheqBTDxXhTisdA8hgvbEG1hHOQ9xmNjeUJSoi6DU/gMrKNcfZjHkyY6Alnuyc+ikYJaxxfHkT3+WuQ==",
|
||||
"version": "5.14.2",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz",
|
||||
"integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==",
|
||||
"requires": {
|
||||
"@jridgewell/source-map": "^0.3.2",
|
||||
"acorn": "^8.5.0",
|
||||
|
||||
+5
-2
@@ -22,10 +22,12 @@
|
||||
"react-router": "^6.3.0",
|
||||
"react-router-dom": "^6.3.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"web-vitals": "^2.1.4"
|
||||
"web-vitals": "^2.1.4",
|
||||
"terser": ">=5.14.2"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "set HTTPS=true&&react-scripts start",
|
||||
"dev": "start npm start && cd ../server && start dotnet run",
|
||||
"build": "CI=false && react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
@@ -51,6 +53,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint-config-react-app": "^7.0.1",
|
||||
"jest-editor-support": "^30.1.0"
|
||||
"jest-editor-support": "^30.1.0",
|
||||
"terser": ">=5.14.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
using FluentAssertions;
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
namespace server.tests.Helpers
|
||||
{
|
||||
internal static class AssertHelper
|
||||
{
|
||||
public static void CheckForRateLimitingHeaders(HttpResponseHeaders headers)
|
||||
{
|
||||
headers.Should().ContainKey("X-Rate-Limit-Limit");
|
||||
headers.Should().ContainKey("X-Rate-Limit-Remaining");
|
||||
headers.Should().ContainKey("X-Rate-Limit-Reset");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
|
||||
namespace server.tests.Http
|
||||
{
|
||||
internal static class HttpClientFactory
|
||||
{
|
||||
public static HttpClient GetClient(int version)
|
||||
{
|
||||
var webAppFactory = new WebApplicationFactory<Program>();
|
||||
|
||||
var client = webAppFactory.CreateDefaultClient();
|
||||
|
||||
client.DefaultRequestHeaders.Add("x-api-version", version.ToString());
|
||||
|
||||
return client;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace server.tests.Options
|
||||
{
|
||||
internal static class OptionsFactory
|
||||
{
|
||||
public static JsonSerializerOptions GetJsonSerializerOptions()
|
||||
{
|
||||
return new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using server.Models;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace server.tests.integrationTests
|
||||
{
|
||||
public class CharactersControllerIntegrationTests
|
||||
{
|
||||
private readonly HttpClient _client;
|
||||
private readonly JsonSerializerOptions _serializerOptions;
|
||||
private readonly string _endpoint;
|
||||
|
||||
public CharactersControllerIntegrationTests()
|
||||
{
|
||||
var webAppFactory = new WebApplicationFactory<Program>();
|
||||
|
||||
_client = webAppFactory.CreateDefaultClient();
|
||||
|
||||
_client.DefaultRequestHeaders.Add("x-api-version", "1");
|
||||
|
||||
_serializerOptions = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
_endpoint = "/api/characters";
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharactersAsync_AllCharacters_Returns200StatusCodeWithCharacters()
|
||||
{
|
||||
var response = await _client.GetAsync(_endpoint);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var characters = JsonSerializer.Deserialize<List<Character>>(data);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
response.Headers.Should().ContainKey("X-Rate-Limit-Limit");
|
||||
response.Headers.Should().ContainKey("X-Rate-Limit-Remaining");
|
||||
response.Headers.Should().ContainKey("X-Rate-Limit-Reset");
|
||||
|
||||
characters.Should().NotBeNull();
|
||||
characters.Should().BeOfType<List<Character>>();
|
||||
characters.Should().HaveCountGreaterThan(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharactersAsync_SeasonOneCharacters_Returns200StatusCodeWithCharacters()
|
||||
{
|
||||
var seasonValue = 1;
|
||||
|
||||
var url = $"{_endpoint}?season={seasonValue}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var characters = JsonSerializer.Deserialize<List<Character>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
response.Headers.Should().ContainKey("X-Rate-Limit-Limit");
|
||||
response.Headers.Should().ContainKey("X-Rate-Limit-Remaining");
|
||||
response.Headers.Should().ContainKey("X-Rate-Limit-Reset");
|
||||
|
||||
characters.Should().NotBeNull();
|
||||
characters.Should().BeOfType<List<Character>>();
|
||||
characters.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var character in characters)
|
||||
{
|
||||
character.Seasons.Should().Contain(seasonValue);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharactersAsync_InvalidSeasonQueryParameter_Returns400StatusCodeWithValidationProblemDetails()
|
||||
{
|
||||
var seasonValue = "test";
|
||||
|
||||
var url = $"{_endpoint}?season={seasonValue}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var details = JsonSerializer.Deserialize<ValidationProblemDetails>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
||||
response.Headers.Should().ContainKey("X-Rate-Limit-Limit");
|
||||
response.Headers.Should().ContainKey("X-Rate-Limit-Remaining");
|
||||
response.Headers.Should().ContainKey("X-Rate-Limit-Reset");
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ValidationProblemDetails>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharactersAsync_NameContainsJason_Returns200StatusCodeWithCharacters()
|
||||
{
|
||||
var nameValue = "jason";
|
||||
|
||||
var url = $"{_endpoint}?name={nameValue}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var characters = JsonSerializer.Deserialize<List<Character>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
response.Headers.Should().ContainKey("X-Rate-Limit-Limit");
|
||||
response.Headers.Should().ContainKey("X-Rate-Limit-Remaining");
|
||||
response.Headers.Should().ContainKey("X-Rate-Limit-Reset");
|
||||
|
||||
characters.Should().NotBeNull();
|
||||
characters.Should().BeOfType<List<Character>>();
|
||||
characters.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var character in characters)
|
||||
{
|
||||
character.FullName.ToLower().Should().Contain(nameValue);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharactersAsync_ActorNameContainsMandy_Returns200StatusCodeWithCharacters()
|
||||
{
|
||||
var actorNameValue = "mandy";
|
||||
|
||||
var url = $"{_endpoint}?actorname={actorNameValue}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var characters = JsonSerializer.Deserialize<List<Character>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
response.Headers.Should().ContainKey("X-Rate-Limit-Limit");
|
||||
response.Headers.Should().ContainKey("X-Rate-Limit-Remaining");
|
||||
response.Headers.Should().ContainKey("X-Rate-Limit-Reset");
|
||||
|
||||
characters.Should().NotBeNull();
|
||||
characters.Should().BeOfType<List<Character>>();
|
||||
characters.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var character in characters)
|
||||
{
|
||||
character.ActorFullName.ToLower().Should().Contain(actorNameValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Moq;
|
||||
using server.Controllers.v1;
|
||||
using server.Models;
|
||||
using server.Persistence.Repositories;
|
||||
using System.Net;
|
||||
|
||||
namespace server.tests.unitTests
|
||||
{
|
||||
public class CharacterControllerUnitTests
|
||||
{
|
||||
private readonly Mock<ICharacterRepository> _mockRepo;
|
||||
private readonly CharactersController _controller;
|
||||
|
||||
public CharacterControllerUnitTests()
|
||||
{
|
||||
_mockRepo = new Mock<ICharacterRepository>();
|
||||
_controller = new CharactersController(_mockRepo.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharactersAsync_AllCharacters_Returns200StatusCodeWithCharactersCollection()
|
||||
{
|
||||
var filter = new CharacterFilter();
|
||||
|
||||
var characters = new List<Character> {new Character(), new Character()};
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetCharactersAsync(filter))
|
||||
.ReturnsAsync(characters);
|
||||
|
||||
var response = await _controller.GetCharactersAsync(filter) as ObjectResult;
|
||||
var data = response.Value as List<Character>;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetCharactersAsync(It.IsAny<CharacterFilter>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<OkObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.OK);
|
||||
|
||||
data.Should().NotBeNull();
|
||||
data.Should().BeOfType<List<Character>>();
|
||||
data.Should().HaveCount(2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharactersAsync_RepoThrowsException_Returns500StatusCodeWithProblemDetails()
|
||||
{
|
||||
var filter = new CharacterFilter();
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetCharactersAsync(filter))
|
||||
.Throws(new Exception());
|
||||
|
||||
var response = await _controller.GetCharactersAsync(filter) as ObjectResult;
|
||||
|
||||
var details = response.Value;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetCharactersAsync(It.IsAny<CharacterFilter>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<ObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.InternalServerError);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ProblemDetails>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using MongoDB.Bson;
|
||||
using server.Models;
|
||||
using server.tests.Helpers;
|
||||
using server.tests.Http;
|
||||
using server.tests.Options;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace server.tests.v1.IntegrationTests
|
||||
{
|
||||
public class CharactersControllerIntegrationTests
|
||||
{
|
||||
private readonly HttpClient _client;
|
||||
private readonly JsonSerializerOptions _serializerOptions;
|
||||
private readonly string _endpoint;
|
||||
|
||||
public CharactersControllerIntegrationTests()
|
||||
{
|
||||
_client = HttpClientFactory.GetClient(1);
|
||||
|
||||
_serializerOptions = OptionsFactory.GetJsonSerializerOptions();
|
||||
|
||||
_endpoint = "/api/characters";
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharactersAsync_AllCharacters_Returns200StatusCodeWithCharacters()
|
||||
{
|
||||
var response = await _client.GetAsync(_endpoint);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var characters = JsonSerializer.Deserialize<List<Character>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
characters.Should().NotBeNull();
|
||||
characters.Should().BeOfType<List<Character>>();
|
||||
characters.Should().HaveCountGreaterThan(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharactersAsync_SeasonOneCharacters_Returns200StatusCodeWithCharacters()
|
||||
{
|
||||
var season = 1;
|
||||
|
||||
var url = $"{_endpoint}?{nameof(season)}={season}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var characters = JsonSerializer.Deserialize<List<Character>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
characters.Should().NotBeNull();
|
||||
characters.Should().BeOfType<List<Character>>();
|
||||
characters.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var character in characters)
|
||||
{
|
||||
character.Seasons.Should().Contain(season);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharactersAsync_InvalidSeasonQueryParameter_Returns400StatusCodeWithValidationProblemDetails()
|
||||
{
|
||||
var season = "test";
|
||||
|
||||
var url = $"{_endpoint}?{nameof(season)}={season}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var details = JsonSerializer.Deserialize<ValidationProblemDetails>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ValidationProblemDetails>();
|
||||
details.Errors.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharactersAsync_NameContainsJason_Returns200StatusCodeWithCharacters()
|
||||
{
|
||||
var name = "jason";
|
||||
|
||||
var url = $"{_endpoint}?{nameof(name)}={name}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var characters = JsonSerializer.Deserialize<List<Character>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
characters.Should().NotBeNull();
|
||||
characters.Should().BeOfType<List<Character>>();
|
||||
characters.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var character in characters)
|
||||
{
|
||||
character.FullName.ToLower().Should().Contain(name);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharactersAsync_ActorNameContainsMandy_Returns200StatusCodeWithCharacters()
|
||||
{
|
||||
var actorName = "mandy";
|
||||
|
||||
var url = $"{_endpoint}?{nameof(actorName)}={actorName}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var characters = JsonSerializer.Deserialize<List<Character>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
characters.Should().NotBeNull();
|
||||
characters.Should().BeOfType<List<Character>>();
|
||||
characters.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var character in characters)
|
||||
{
|
||||
character.ActorFullName.ToLower().Should().Contain(actorName);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharacterByIdAsync_ValidCharacterId_Returns200StatusCodeWithCharacter()
|
||||
{
|
||||
var response = await _client.GetAsync(_endpoint);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var characters = JsonSerializer.Deserialize<List<Character>>(data, _serializerOptions);
|
||||
|
||||
var characterId = characters[0].Id;
|
||||
|
||||
var url = $"{_endpoint}/{characterId}";
|
||||
|
||||
response = await _client.GetAsync(url);
|
||||
|
||||
data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var character = JsonSerializer.Deserialize<Character>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
character.Should().NotBeNull();
|
||||
character.Should().BeOfType<Character>();
|
||||
character.Id.Should().Be(characterId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharacterByIdAsync_InvalidCharacterId_Returns400StatusCodeWithValidationProblemDetails()
|
||||
{
|
||||
var characterId = "1";
|
||||
|
||||
var url = $"{_endpoint}/{characterId}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var details = JsonSerializer.Deserialize<ValidationProblemDetails>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ValidationProblemDetails>();
|
||||
details.Detail.Should().NotBeNull();
|
||||
details.Errors.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharacterByIdAsync_ValidCharacterIdForNonExistentCharacter_Returns404StatusCodeWithProblemDetails()
|
||||
{
|
||||
var characterId = ObjectId.GenerateNewId();
|
||||
|
||||
var url = $"{_endpoint}/{characterId}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var details = JsonSerializer.Deserialize<ProblemDetails>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ProblemDetails>();
|
||||
details.Detail.Should().NotBeNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,437 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using server.Models;
|
||||
using server.tests.Helpers;
|
||||
using server.tests.Http;
|
||||
using server.tests.Options;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace server.tests.v1.IntegrationTests
|
||||
{
|
||||
public class EpisodesControllerIntegrationTests
|
||||
{
|
||||
private readonly HttpClient _client;
|
||||
private readonly JsonSerializerOptions _serializerOptions;
|
||||
private readonly string _endpoint;
|
||||
|
||||
public EpisodesControllerIntegrationTests()
|
||||
{
|
||||
_client = HttpClientFactory.GetClient(1);
|
||||
|
||||
_serializerOptions = OptionsFactory.GetJsonSerializerOptions();
|
||||
|
||||
_endpoint = "/api/episodes";
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_AllEpisodes_Returns200StatusCodeWithEpisodes()
|
||||
{
|
||||
var response = await _client.GetAsync(_endpoint);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var episodes = JsonSerializer.Deserialize<List<Episode>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
episodes.Should().NotBeNull();
|
||||
episodes.Should().BeOfType<List<Episode>>();
|
||||
episodes.Should().HaveCountGreaterThan(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_SeasonOneEpisodes_Returns200StatusCodeWithEpisodes()
|
||||
{
|
||||
var season = 1;
|
||||
|
||||
var url = $"{_endpoint}?{nameof(season)}={season}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var episodes = JsonSerializer.Deserialize<List<Episode>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
episodes.Should().NotBeNull();
|
||||
episodes.Should().BeOfType<List<Episode>>();
|
||||
episodes.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var episode in episodes)
|
||||
{
|
||||
episode.Season.Should().Be(season);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_InvalidSeasonQueryParameter_Returns400StatusCodeWithValidationProblemDetails()
|
||||
{
|
||||
var season = "test";
|
||||
|
||||
var url = $"{_endpoint}?{nameof(season)}={season}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var details = JsonSerializer.Deserialize<ValidationProblemDetails>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ValidationProblemDetails>();
|
||||
details.Errors.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_EpisodesAfterJanuary2020_Returns200StatusCodeWithEpisodes()
|
||||
{
|
||||
var startDate = new DateTime(2020, 1, 1);
|
||||
|
||||
var url = $"{_endpoint}?{nameof(startDate)}={startDate}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var episodes = JsonSerializer.Deserialize<List<Episode>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
episodes.Should().NotBeNull();
|
||||
episodes.Should().BeOfType<List<Episode>>();
|
||||
episodes.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var episode in episodes)
|
||||
{
|
||||
episode.AirDate.Should().BeOnOrAfter(startDate);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_InvalidStartDateQueryParam_Returns400StatusCodeWithValidationProblemDetails()
|
||||
{
|
||||
var startDate = "test";
|
||||
|
||||
var url = $"{_endpoint}?{nameof(startDate)}={startDate}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var details = JsonSerializer.Deserialize<ValidationProblemDetails>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ValidationProblemDetails>();
|
||||
details.Errors.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_EpisodesBeforeJanuary2020_Returns200StatusCodeWithEpisodes()
|
||||
{
|
||||
var endDate = new DateTime(2020, 1, 1);
|
||||
|
||||
var url = $"{_endpoint}?{nameof(endDate)}={endDate}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var episodes = JsonSerializer.Deserialize<List<Episode>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
episodes.Should().NotBeNull();
|
||||
episodes.Should().BeOfType<List<Episode>>();
|
||||
episodes.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var episode in episodes)
|
||||
{
|
||||
episode.AirDate.Should().BeOnOrBefore(endDate);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_InvalidEndDateQueryParam_Returns400StatusCodeWithValidationProblemDetails()
|
||||
{
|
||||
var endDate = "test";
|
||||
|
||||
var url = $"{_endpoint}?{nameof(endDate)}={endDate}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var details = JsonSerializer.Deserialize<ValidationProblemDetails>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ValidationProblemDetails>();
|
||||
details.Errors.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_EpisodeTitlesThatContainThe_Returns200StatusCodeWithEpisodes()
|
||||
{
|
||||
var title = "the";
|
||||
|
||||
var url = $"{_endpoint}?{nameof(title)}={title}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var episodes = JsonSerializer.Deserialize<List<Episode>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
episodes.Should().NotBeNull();
|
||||
episodes.Should().BeOfType<List<Episode>>();
|
||||
episodes.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var episode in episodes)
|
||||
{
|
||||
episode.Title.ToLower().Should().Contain(title);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_EpisodeSummariesThatContainFoyet_Returns200StatusCodeWithEpisodes()
|
||||
{
|
||||
var summaryKeyword = "foyet";
|
||||
|
||||
var url = $"{_endpoint}?{nameof(summaryKeyword)}={summaryKeyword}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var episodes = JsonSerializer.Deserialize<List<Episode>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
episodes.Should().NotBeNull();
|
||||
episodes.Should().BeOfType<List<Episode>>();
|
||||
episodes.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var episode in episodes)
|
||||
{
|
||||
episode.Summary.ToLower().Should().Contain(summaryKeyword);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_EpisodesDirectedByCharles_Returns200StatusCodeWithEpisodes()
|
||||
{
|
||||
var directedBy = "charles";
|
||||
|
||||
var url = $"{_endpoint}?{nameof(directedBy)}={directedBy}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var episodes = JsonSerializer.Deserialize<List<Episode>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
episodes.Should().NotBeNull();
|
||||
episodes.Should().BeOfType<List<Episode>>();
|
||||
episodes.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var episode in episodes)
|
||||
{
|
||||
episode.DirectedBy.ToLower().Should().Contain(directedBy);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_EpisodesWrittenByBreen_Returns200StatusCodeWithEpisodes()
|
||||
{
|
||||
var writtenBy = "breen";
|
||||
|
||||
var url = $"{_endpoint}?{nameof(writtenBy)}={writtenBy}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var episodes = JsonSerializer.Deserialize<List<Episode>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
episodes.Should().NotBeNull();
|
||||
episodes.Should().BeOfType<List<Episode>>();
|
||||
episodes.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var episode in episodes)
|
||||
{
|
||||
episode.WrittenBy.Any(writer => writer.ToLower().Contains(writtenBy)).Should().BeTrue();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_EpisodesWithGreaterThan12MillionUsViewers_Returns200StatusCodeWithEpisodes()
|
||||
{
|
||||
var viewersRangeStart = 12.0;
|
||||
|
||||
var url = $"{_endpoint}?{nameof(viewersRangeStart)}={viewersRangeStart}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var episodes = JsonSerializer.Deserialize<List<Episode>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
episodes.Should().NotBeNull();
|
||||
episodes.Should().BeOfType<List<Episode>>();
|
||||
episodes.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var episode in episodes)
|
||||
{
|
||||
episode.UsViewersInMillions.Should().BeGreaterThanOrEqualTo(viewersRangeStart);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_InvalidViewersRangeStartQueryParam_Returns400StatusCodeWithValidationProblemDetails()
|
||||
{
|
||||
var viewersRangeStart = "test";
|
||||
|
||||
var url = $"{_endpoint}?{nameof(viewersRangeStart)}={viewersRangeStart}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var details = JsonSerializer.Deserialize<ValidationProblemDetails>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ValidationProblemDetails>();
|
||||
details.Errors.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_EpisodesWithLessThan12MillionUsViewers_Returns200StatusCodeWithEpisodes()
|
||||
{
|
||||
var viewersRangeEnd = 12.0;
|
||||
|
||||
var url = $"{_endpoint}?{nameof(viewersRangeEnd)}={viewersRangeEnd}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var episodes = JsonSerializer.Deserialize<List<Episode>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
episodes.Should().NotBeNull();
|
||||
episodes.Should().BeOfType<List<Episode>>();
|
||||
episodes.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var episode in episodes)
|
||||
{
|
||||
episode.UsViewersInMillions.Should().BeLessThanOrEqualTo(viewersRangeEnd);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_InvalidViewersRangeEndQueryParam_Returns400StatusCodeWithValidationProblemDetails()
|
||||
{
|
||||
var viewersRangeEnd = "test";
|
||||
|
||||
var url = $"{_endpoint}?{nameof(viewersRangeEnd)}={viewersRangeEnd}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var details = JsonSerializer.Deserialize<ValidationProblemDetails>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ValidationProblemDetails>();
|
||||
details.Errors.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodeByNumberAsync_ValidEpisodeNumber_Returns200StatusCodeWithEpisode()
|
||||
{
|
||||
var episodeNumber = 1;
|
||||
|
||||
var url = $"{_endpoint}/{episodeNumber}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var episode = JsonSerializer.Deserialize<Episode>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
episode.Should().NotBeNull();
|
||||
episode.Should().BeOfType<Episode>();
|
||||
episode.NumberInSeries.Should().Be(episodeNumber);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodeByNumberAsync_InvalidEpisodeNumber_Returns404StatusCode()
|
||||
{
|
||||
var episodeNumber = "test";
|
||||
|
||||
var url = $"{_endpoint}/{episodeNumber}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodeByNumberAsync_ValidEpisodeNumberForNonExistentEpisode_Returns404StatusCodeWithProblemDetails()
|
||||
{
|
||||
var episodeNumber = 10000;
|
||||
|
||||
var url = $"{_endpoint}/{episodeNumber}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var details = JsonSerializer.Deserialize<ProblemDetails>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ProblemDetails>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using MongoDB.Bson;
|
||||
using server.Models;
|
||||
using server.tests.Helpers;
|
||||
using server.tests.Http;
|
||||
using server.tests.Options;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace server.tests.v1.IntegrationTests
|
||||
{
|
||||
public class QuotesControllerIntegrationTests
|
||||
{
|
||||
private readonly HttpClient _client;
|
||||
private readonly JsonSerializerOptions _serializerOptions;
|
||||
private readonly string _endpoint;
|
||||
|
||||
public QuotesControllerIntegrationTests()
|
||||
{
|
||||
_client = HttpClientFactory.GetClient(1);
|
||||
|
||||
_serializerOptions = OptionsFactory.GetJsonSerializerOptions();
|
||||
|
||||
_endpoint = "/api/quotes";
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetQuotesAsync_AllQuotes_Returns200StatusCodeWithQuotes()
|
||||
{
|
||||
var response = await _client.GetAsync(_endpoint);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var characters = JsonSerializer.Deserialize<List<Quote>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
characters.Should().NotBeNull();
|
||||
characters.Should().BeOfType<List<Quote>>();
|
||||
characters.Should().HaveCountGreaterThan(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetQuotesAsync_SeasonOneQuotes_Returns200StatusCodeWithQoutes()
|
||||
{
|
||||
var season = 1;
|
||||
|
||||
var url = $"{_endpoint}?{nameof(season)}={season}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var quotes = JsonSerializer.Deserialize<List<Quote>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
quotes.Should().NotBeNull();
|
||||
quotes.Should().BeOfType<List<Quote>>();
|
||||
quotes.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var quote in quotes)
|
||||
{
|
||||
quote.Season.Should().Be(season);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetQuotesAsync_InvalidSeasonQueryParameter_Returns400StatusCodeWithValidationProblemDetails()
|
||||
{
|
||||
var season = "test";
|
||||
|
||||
var url = $"{_endpoint}?{nameof(season)}={season}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var details = JsonSerializer.Deserialize<ValidationProblemDetails>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ValidationProblemDetails>();
|
||||
details.Errors.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetQuotesAsync_EpisodeOneQuotes_Returns200StatusCodeWithQuotes()
|
||||
{
|
||||
var episode = 1;
|
||||
|
||||
var url = $"{_endpoint}?{nameof(episode)}={episode}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var quotes = JsonSerializer.Deserialize<List<Quote>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
quotes.Should().NotBeNull();
|
||||
quotes.Should().BeOfType<List<Quote>>();
|
||||
quotes.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var quote in quotes)
|
||||
{
|
||||
quote.Episode.Should().Be(episode);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetQuotesAsync_InvalidEpisodeQueryParameter_Returns400StatusCodeWithValidationProblemDetails()
|
||||
{
|
||||
var episode = "test";
|
||||
|
||||
var url = $"{_endpoint}?{nameof(episode)}={episode}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var details = JsonSerializer.Deserialize<ValidationProblemDetails>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ValidationProblemDetails>();
|
||||
details.Errors.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetQuotesAsync_QuotesThatContainEvil_Returns200StatusCodeWithQuotes()
|
||||
{
|
||||
var textKeyword = "evil";
|
||||
|
||||
var url = $"{_endpoint}?{nameof(textKeyword)}={textKeyword}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var quotes = JsonSerializer.Deserialize<List<Quote>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
quotes.Should().NotBeNull();
|
||||
quotes.Should().BeOfType<List<Quote>>();
|
||||
quotes.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var quote in quotes)
|
||||
{
|
||||
quote.Text.ToLower().Should().Contain(textKeyword);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetQuotesAsync_QuotesByYoda_Returns200StatusCodeWithQuotes()
|
||||
{
|
||||
var source = "yoda";
|
||||
|
||||
var url = $"{_endpoint}?{nameof(source)}={source}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var quotes = JsonSerializer.Deserialize<List<Quote>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
quotes.Should().NotBeNull();
|
||||
quotes.Should().BeOfType<List<Quote>>();
|
||||
quotes.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var quote in quotes)
|
||||
{
|
||||
quote.Source.ToLower().Should().Contain(source);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetQuotesAsync_QuotesNarratedByJason_Returns200StatusCodeWithQuotes()
|
||||
{
|
||||
var narrator = "jason";
|
||||
|
||||
var url = $"{_endpoint}?{nameof(narrator)}={narrator}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var quotes = JsonSerializer.Deserialize<List<Quote>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
quotes.Should().NotBeNull();
|
||||
quotes.Should().BeOfType<List<Quote>>();
|
||||
quotes.Should().HaveCountGreaterThan(0);
|
||||
|
||||
foreach (var quote in quotes)
|
||||
{
|
||||
quote.Narrator.ToLower().Should().Contain(narrator);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetQuotesById_ValidQuoteId_Returns200StatusCodeWithQuote()
|
||||
{
|
||||
var response = await _client.GetAsync(_endpoint);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var quotes = JsonSerializer.Deserialize<List<Quote>>(data, _serializerOptions);
|
||||
|
||||
var quoteId = quotes[0].Id;
|
||||
|
||||
var url = $"{_endpoint}/{quoteId}";
|
||||
|
||||
response = await _client.GetAsync(url);
|
||||
|
||||
data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var quote = JsonSerializer.Deserialize<Quote>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
quote.Should().NotBeNull();
|
||||
quote.Should().BeOfType<Quote>();
|
||||
quote.Id.Should().Be(quoteId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetQuotesById_InvalidQuoteId_Returns400StatusCodeWithValidationProblemDetails()
|
||||
{
|
||||
var quoteId = "1";
|
||||
|
||||
var url = $"{_endpoint}/{quoteId}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var details = JsonSerializer.Deserialize<ValidationProblemDetails>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ValidationProblemDetails>();
|
||||
details.Detail.Should().NotBeNull();
|
||||
details.Errors.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetQuoteByIdAsync_ValidQuoteIdForNonExistentQuote_Returns404StatusCodeWithProblemDetails()
|
||||
{
|
||||
var quoteId = ObjectId.GenerateNewId();
|
||||
|
||||
var url = $"{_endpoint}/{quoteId}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var details = JsonSerializer.Deserialize<ProblemDetails>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ProblemDetails>();
|
||||
details.Detail.Should().NotBeNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using server.Models;
|
||||
using server.tests.Helpers;
|
||||
using server.tests.Http;
|
||||
using server.tests.Options;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace server.tests.v1.IntegrationTests
|
||||
{
|
||||
public class SeasonsControllerIntegrationTests
|
||||
{
|
||||
private readonly HttpClient _client;
|
||||
private readonly JsonSerializerOptions _serializerOptions;
|
||||
private readonly string _endpoint;
|
||||
|
||||
public SeasonsControllerIntegrationTests()
|
||||
{
|
||||
_client = HttpClientFactory.GetClient(1);
|
||||
|
||||
_serializerOptions = OptionsFactory.GetJsonSerializerOptions();
|
||||
|
||||
_endpoint = "/api/seasons";
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSeasonsAsync_AllSeasons_Returns200StatusCodeWithSeasons()
|
||||
{
|
||||
var response = await _client.GetAsync(_endpoint);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var seasons = JsonSerializer.Deserialize<List<Season>>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
seasons.Should().NotBeNull();
|
||||
seasons.Should().BeOfType<List<Season>>();
|
||||
seasons.Should().HaveCountGreaterThan(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSeasonByNumberAsync_SeasonOne_Returns200StatusCodeWithSeason()
|
||||
{
|
||||
var seasonNumber = 1;
|
||||
|
||||
var url = $"{_endpoint}/{seasonNumber}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var season = JsonSerializer.Deserialize<Season>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
season.Should().NotBeNull();
|
||||
season.Should().BeOfType<Season>();
|
||||
season.SeasonNumber.Should().Be(seasonNumber);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSeasonByNumberAsync_InvalidSeason_Returns404StatusCode()
|
||||
{
|
||||
var seasonNumber = "test";
|
||||
|
||||
var url = $"{_endpoint}/{seasonNumber}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSeasonByNumberAsync_ValidSeasonNumberForNonExistentSeason_Returns404StatusCode()
|
||||
{
|
||||
var seasonNumber = 20;
|
||||
|
||||
var url = $"{_endpoint}/{seasonNumber}";
|
||||
|
||||
var response = await _client.GetAsync(url);
|
||||
|
||||
var data = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var details = JsonSerializer.Deserialize<ProblemDetails>(data, _serializerOptions);
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
||||
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ProblemDetails>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Moq;
|
||||
using server.Controllers.v1;
|
||||
using server.Models;
|
||||
using server.Persistence.Repositories;
|
||||
using System.Net;
|
||||
|
||||
namespace server.tests.v1.UnitTests
|
||||
{
|
||||
public class CharactersControllerUnitTests
|
||||
{
|
||||
private readonly Mock<ICharacterRepository> _mockRepo;
|
||||
private readonly CharactersController _controller;
|
||||
|
||||
public CharactersControllerUnitTests()
|
||||
{
|
||||
_mockRepo = new Mock<ICharacterRepository>();
|
||||
_controller = new CharactersController(_mockRepo.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharactersAsync_AllCharacters_Returns200StatusCodeWithCharactersCollection()
|
||||
{
|
||||
var filter = new CharacterFilter();
|
||||
|
||||
var characters = new List<Character> { new Character(), new Character() };
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetCharactersAsync(filter))
|
||||
.ReturnsAsync(characters);
|
||||
|
||||
var response = await _controller.GetCharactersAsync(filter) as ObjectResult;
|
||||
var data = response.Value as List<Character>;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetCharactersAsync(It.IsAny<CharacterFilter>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<OkObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.OK);
|
||||
|
||||
data.Should().NotBeNull();
|
||||
data.Should().BeOfType<List<Character>>();
|
||||
data.Should().HaveCount(2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharactersAsync_RepoThrowsException_Returns500StatusCodeWithProblemDetails()
|
||||
{
|
||||
var filter = new CharacterFilter();
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetCharactersAsync(filter))
|
||||
.Throws(new Exception());
|
||||
|
||||
var response = await _controller.GetCharactersAsync(filter) as ObjectResult;
|
||||
|
||||
var details = response.Value;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetCharactersAsync(It.IsAny<CharacterFilter>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<ObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.InternalServerError);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ProblemDetails>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharacterByIdAsync_ValidCharacterId_Returns200StatusCodeWithCharacter()
|
||||
{
|
||||
var characterId = "62b7d5506c1b407771829926";
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetCharacterByIdAsync(characterId))
|
||||
.ReturnsAsync(new Character());
|
||||
|
||||
var response = await _controller.GetCharacterByIdAsync(characterId) as ObjectResult;
|
||||
|
||||
var character = response.Value;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetCharacterByIdAsync(It.IsAny<string>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<OkObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.OK);
|
||||
|
||||
character.Should().NotBeNull();
|
||||
character.Should().BeOfType<Character>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharacterByIdAsync_ValidCharacterIdForNonExistentCharacter_Returns404StatusCodeWithProblemDetails()
|
||||
{
|
||||
var characterId = "62b7d5506c1b407771829926";
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetCharacterByIdAsync(characterId))
|
||||
.ReturnsAsync(null as Character);
|
||||
|
||||
var response = await _controller.GetCharacterByIdAsync(characterId) as ObjectResult;
|
||||
|
||||
var details = response.Value;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetCharacterByIdAsync(It.IsAny<string>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<ObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.NotFound);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ProblemDetails>();
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharacterByIdAsync_RepoThrowsException_Returns500StatusCodeWithProblemDetails()
|
||||
{
|
||||
var characterId = "62b7d5506c1b407771829926";
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetCharacterByIdAsync(characterId))
|
||||
.Throws(new Exception());
|
||||
|
||||
var response = await _controller.GetCharacterByIdAsync(characterId) as ObjectResult;
|
||||
|
||||
var details = response.Value;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetCharacterByIdAsync(It.IsAny<string>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<ObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.InternalServerError);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ProblemDetails>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Moq;
|
||||
using server.Controllers.v1;
|
||||
using server.Models;
|
||||
using server.Persistence.Repositories;
|
||||
using System.Net;
|
||||
|
||||
namespace server.tests.v1.UnitTests
|
||||
{
|
||||
public class EpisodesControllerUnitTests
|
||||
{
|
||||
private readonly Mock<IEpisodeRepository> _mockRepo;
|
||||
private readonly EpisodesController _controller;
|
||||
|
||||
public EpisodesControllerUnitTests()
|
||||
{
|
||||
_mockRepo = new Mock<IEpisodeRepository>();
|
||||
_controller = new EpisodesController(_mockRepo.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_AllEpisodes_Returns200StatusCodeWithEpisodesCollection()
|
||||
{
|
||||
var filter = new EpisodeFilter();
|
||||
|
||||
var episodes = new List<Episode> { new Episode(), new Episode() };
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetEpisodesAsync(filter))
|
||||
.ReturnsAsync(episodes);
|
||||
|
||||
var response = await _controller.GetEpisodesAsync(filter) as ObjectResult;
|
||||
|
||||
var data = response.Value as List<Episode>;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetEpisodesAsync(It.IsAny<EpisodeFilter>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<OkObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.OK);
|
||||
|
||||
data.Should().NotBeNull();
|
||||
data.Should().BeOfType<List<Episode>>();
|
||||
data.Should().HaveCount(2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodesAsync_RepoThrowsException_Returns500StatusCodeWithProblemDetails()
|
||||
{
|
||||
var filter = new EpisodeFilter();
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetEpisodesAsync(filter))
|
||||
.Throws(new Exception());
|
||||
|
||||
var response = await _controller.GetEpisodesAsync(filter) as ObjectResult;
|
||||
|
||||
var details = response.Value;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetEpisodesAsync(It.IsAny<EpisodeFilter>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<ObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.InternalServerError);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ProblemDetails>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodeByNumberAsync_ValidEpisodeNumber_Returns200StatusWithEpisode()
|
||||
{
|
||||
var episodeNumber = 1;
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetEpisodeByNumberAsync(episodeNumber))
|
||||
.ReturnsAsync(new Episode());
|
||||
|
||||
var response = await _controller.GetEpisodeByNumberAsync(episodeNumber) as ObjectResult;
|
||||
|
||||
var episode = response.Value;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetEpisodeByNumberAsync(It.IsAny<int>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<OkObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.OK);
|
||||
|
||||
episode.Should().NotBeNull();
|
||||
episode.Should().BeOfType<Episode>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodeByNumberAsync_ValidEpisodeNumberForNonExistentEpisode_Returns404StatusWithProblemDetails()
|
||||
{
|
||||
var episodeNumber = 3000;
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetEpisodeByNumberAsync(episodeNumber))
|
||||
.ReturnsAsync(null as Episode);
|
||||
|
||||
var response = await _controller.GetEpisodeByNumberAsync(episodeNumber) as ObjectResult;
|
||||
|
||||
var details = response.Value;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetEpisodeByNumberAsync(It.IsAny<int>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<ObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.NotFound);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ProblemDetails>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpisodeByNumberAsync_RepoThrowsException_Returns500StatusCodeWithProblemDetails()
|
||||
{
|
||||
var episodeNumber = 1;
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetEpisodeByNumberAsync(episodeNumber))
|
||||
.Throws(new Exception());
|
||||
|
||||
var response = await _controller.GetEpisodeByNumberAsync(episodeNumber) as ObjectResult;
|
||||
|
||||
var details = response.Value;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetEpisodeByNumberAsync(It.IsAny<int>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<ObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.InternalServerError);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ProblemDetails>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Moq;
|
||||
using server.Controllers.v1;
|
||||
using server.Models;
|
||||
using server.Persistence.Repositories;
|
||||
using System.Net;
|
||||
|
||||
namespace server.tests.v1.UnitTests
|
||||
{
|
||||
public class QuotesControllerUnitTests
|
||||
{
|
||||
private readonly Mock<IQuoteRepository> _mockRepo;
|
||||
private readonly QuotesController _controller;
|
||||
|
||||
public QuotesControllerUnitTests()
|
||||
{
|
||||
_mockRepo = new Mock<IQuoteRepository>();
|
||||
_controller = new QuotesController(_mockRepo.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetQuotesAsync_AllQuotes_Returns200StatusCodeWithQuotesCollection()
|
||||
{
|
||||
var filter = new QuoteFilter();
|
||||
|
||||
var quotes = new List<Quote> { new Quote(), new Quote() };
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetQuotesAsync(filter))
|
||||
.ReturnsAsync(quotes);
|
||||
|
||||
var response = await _controller.GetQuotesAsync(filter) as ObjectResult;
|
||||
|
||||
var data = response.Value as List<Quote>;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetQuotesAsync(It.IsAny<QuoteFilter>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<OkObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.OK);
|
||||
|
||||
data.Should().NotBeNull();
|
||||
data.Should().BeOfType<List<Quote>>();
|
||||
data.Should().HaveCount(2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetQuotesAsync_RepoThrowsException_Returns500StatusCodeWithProblemDetails()
|
||||
{
|
||||
var filter = new QuoteFilter();
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetQuotesAsync(filter))
|
||||
.Throws(new Exception());
|
||||
|
||||
var response = await _controller.GetQuotesAsync(filter) as ObjectResult;
|
||||
|
||||
var details = response.Value;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetQuotesAsync(It.IsAny<QuoteFilter>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<ObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.InternalServerError);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ProblemDetails>();
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task GetQuoteByIdAsync_ValidId_Returns200StatusCodeWithQuote()
|
||||
{
|
||||
var quoteId = "62b7d5506c1b407771829926";
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetQuoteByIdAsync(quoteId))
|
||||
.ReturnsAsync(new Quote());
|
||||
|
||||
var response = await _controller.GetQuoteByIdAsync(quoteId) as ObjectResult;
|
||||
|
||||
var character = response.Value;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetQuoteByIdAsync(It.IsAny<string>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<OkObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.OK);
|
||||
|
||||
character.Should().NotBeNull();
|
||||
character.Should().BeOfType<Quote>();
|
||||
}
|
||||
|
||||
public async Task GetQuoteByIdAsync_ValidIdForNonExistentQuote_Returns404StatusCodeWithProblemDetails()
|
||||
{
|
||||
var quoteId = "62b7d5506c1b407771829926";
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetQuoteByIdAsync(quoteId))
|
||||
.ReturnsAsync(null as Quote);
|
||||
|
||||
var response = await _controller.GetQuoteByIdAsync(quoteId) as ObjectResult;
|
||||
|
||||
var quote = response.Value;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetQuoteByIdAsync(It.IsAny<String>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<OkObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.NotFound);
|
||||
|
||||
quote.Should().NotBeNull();
|
||||
quote.Should().BeOfType<Quote>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetQuoteByIdAsync_RepoThrowsException_Returns500StatusCodeWithProblemDetails()
|
||||
{
|
||||
var quoteId = "62b7d5506c1b407771829926";
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetQuoteByIdAsync(quoteId))
|
||||
.Throws(new Exception());
|
||||
|
||||
var response = await _controller.GetQuoteByIdAsync(quoteId) as ObjectResult;
|
||||
|
||||
var details = response.Value;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetQuoteByIdAsync(It.IsAny<string>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<ObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.InternalServerError);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ProblemDetails>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Moq;
|
||||
using server.Controllers.v1;
|
||||
using server.Models;
|
||||
using server.Persistence.Repositories;
|
||||
using System.Net;
|
||||
|
||||
namespace server.tests.v1.UnitTests
|
||||
{
|
||||
public class SeasonsControllerUnitTests
|
||||
{
|
||||
private readonly Mock<ISeasonRepository> _mockRepo;
|
||||
private readonly SeasonsController _controller;
|
||||
|
||||
public SeasonsControllerUnitTests()
|
||||
{
|
||||
_mockRepo = new Mock<ISeasonRepository>();
|
||||
_controller = new SeasonsController(_mockRepo.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSeasonsAsync_AllSeasons_Returns200StatusCodeWithSeasonsCollection()
|
||||
{
|
||||
var seasons = new List<Season> { new Season(), new Season() };
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetSeasonsAsync())
|
||||
.ReturnsAsync(seasons);
|
||||
|
||||
var response = await _controller.GetSeasonsAsync() as ObjectResult;
|
||||
|
||||
var data = response.Value as List<Season>;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetSeasonsAsync(), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<OkObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.OK);
|
||||
|
||||
data.Should().NotBeNull();
|
||||
data.Should().BeOfType<List<Season>>();
|
||||
data.Should().HaveCount(2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSeasonsAsync_RepoThrowsException_Returns500StatusCodeWithProblemDetails()
|
||||
{
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetSeasonsAsync())
|
||||
.Throws(new Exception());
|
||||
|
||||
var response = await _controller.GetSeasonsAsync() as ObjectResult;
|
||||
|
||||
var details = response.Value;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetSeasonsAsync(), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<ObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.InternalServerError);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ProblemDetails>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSeasonByNumberAsync_ValidSeasonNumber_Returns200StatusCodeWithSeason()
|
||||
{
|
||||
var seasonNumber = 1;
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetSeasonByNumberAsync(seasonNumber))
|
||||
.ReturnsAsync(new Season());
|
||||
|
||||
var response = await _controller.GetSeasonByNumberAsync(seasonNumber) as ObjectResult;
|
||||
|
||||
var season = response.Value;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetSeasonByNumberAsync(It.IsAny<int>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<OkObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.OK);
|
||||
|
||||
season.Should().NotBeNull();
|
||||
season.Should().BeOfType<Season>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSeasonByNumberAsync_ValidSeasonNumberForNonExistentSeason_Returns404StatusCodeWithProblemDetails()
|
||||
{
|
||||
var seasonNumber = 20;
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetSeasonByNumberAsync(seasonNumber))
|
||||
.ReturnsAsync(null as Season);
|
||||
|
||||
var response = await _controller.GetSeasonByNumberAsync(seasonNumber) as ObjectResult;
|
||||
|
||||
var details = response.Value;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetSeasonByNumberAsync(It.IsAny<int>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<ObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.NotFound);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ProblemDetails>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSeasonByNumberAsync_RepoThrowsException_Returns500StatusCodeWithProblemDetails()
|
||||
{
|
||||
var seasonNumber = 1;
|
||||
|
||||
_mockRepo
|
||||
.Setup(repo => repo.GetSeasonByNumberAsync(seasonNumber))
|
||||
.Throws(new Exception());
|
||||
|
||||
var response = await _controller.GetSeasonByNumberAsync(seasonNumber) as ObjectResult;
|
||||
|
||||
var details = response.Value;
|
||||
|
||||
_mockRepo.Verify(repo => repo.GetSeasonByNumberAsync(It.IsAny<int>()), Times.Once());
|
||||
|
||||
response.Should().NotBeNull();
|
||||
response.Should().BeOfType<ObjectResult>();
|
||||
response.StatusCode.Should().Be((int)HttpStatusCode.InternalServerError);
|
||||
|
||||
details.Should().NotBeNull();
|
||||
details.Should().BeOfType<ProblemDetails>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ namespace server.Controllers.v1
|
||||
if (!ObjectId.TryParse(id, out _))
|
||||
{
|
||||
ModelState.AddModelError(nameof(id), $"{id} is not a valid id");
|
||||
return ValidationProblem();
|
||||
return ValidationProblem(detail: "Invalid request");
|
||||
}
|
||||
|
||||
try
|
||||
|
||||
@@ -49,14 +49,12 @@ namespace server.Controllers.v1
|
||||
/// </summary>
|
||||
/// <param name="number">The number of the episode in the series.</param>
|
||||
/// <response code="200">Returns the episode requested.</response>
|
||||
/// <response code="400">Not a valid request.</response>
|
||||
/// <response code="404">Unable to find an episode with the provided number.</response>
|
||||
/// <response code="500">Failed to get episode.</response>
|
||||
/// <returns>Returns the episode requested.</returns>
|
||||
[MapToApiVersion("1.0")]
|
||||
[HttpGet("{number:int}")]
|
||||
[ProducesResponseType(typeof(Episode), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
|
||||
public async Task<IActionResult> GetEpisodeByNumberAsync(int number)
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace server.Controllers.v1
|
||||
if (!ObjectId.TryParse(id, out _))
|
||||
{
|
||||
ModelState.AddModelError(nameof(id), $"{id} is not a valid id");
|
||||
return ValidationProblem();
|
||||
return ValidationProblem(detail: "Invalid request");
|
||||
}
|
||||
|
||||
try
|
||||
|
||||
Reference in New Issue
Block a user