finished writing tests for episodes controller. started writing tests for seasons controller. add http client factory class for integration tests

This commit is contained in:
StevanFreeborn
2022-07-08 16:32:25 -05:00
parent 5985d5d9fc
commit 16fe8039bb
11 changed files with 740 additions and 333 deletions
+3
View File
@@ -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
+20
View File
@@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Mvc.Testing;
namespace server.tests.Http
{
internal static class HttpClientFactory
{
public static HttpClient GetHttpClient(int version)
{
var webAppFactory = new WebApplicationFactory<Program>();
var client = webAppFactory.CreateDefaultClient();
client.DefaultRequestHeaders.Add("x-api-version", version.ToString());
return client;
}
}
}
@@ -1,217 +0,0 @@
using FluentAssertions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Testing;
using server.Models;
using System.Net;
using System.Text.Json;
using server.tests.Helpers;
namespace server.tests.IntegrationTests
{
public class EpisodesControllerIntegrationTests
{
private readonly HttpClient _client;
private readonly JsonSerializerOptions _serializerOptions;
private readonly string _endpoint;
public EpisodesControllerIntegrationTests()
{
var webAppFactory = new WebApplicationFactory<Program>();
_client = webAppFactory.CreateDefaultClient();
_client.DefaultRequestHeaders.Add("x-api-version", "1");
_serializerOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
_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 seasonValue = 1;
var url = $"{_endpoint}?season={seasonValue}";
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(seasonValue);
}
}
[Fact]
public async Task GetEpisodesAsync_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);
AssertHelper.CheckForRateLimitingHeaders(response.Headers);
details.Should().NotBeNull();
details.Should().BeOfType<ValidationProblemDetails>();
details.Errors.Should().NotBeNull();
}
[Fact]
public async Task GetEpisodesAsync_EpisodesAfterJanuary2020_Returns200StatusCodeWithEpisodes()
{
var startDateValue = new DateTime(2020, 1, 1);
var url = $"{_endpoint}?startdate={startDateValue}";
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(startDateValue);
}
}
[Fact]
public async Task GetEpisodesAsync_InvalidStartDateQueryParam_Returns400StatusCodeWithValidationProblemDetails()
{
var startDateValue = "test";
var url = $"{_endpoint}?startdate={startDateValue}";
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 endDateValue = new DateTime(2020, 1, 1);
var url = $"{_endpoint}?enddate={endDateValue}";
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(endDateValue);
}
}
[Fact]
public async Task GetEpisodesAsync_InvalidEndDateQueryParam_Returns400StatusCodeWithValidationProblemDetails()
{
var startDateValue = "test";
var url = $"{_endpoint}?startdate={startDateValue}";
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 titleValue = "the";
var url = $"{_endpoint}?title={titleValue}";
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(titleValue);
}
}
}
}
@@ -1,71 +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 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>();
}
}
}
@@ -6,8 +6,9 @@ using server.Models;
using System.Net;
using System.Text.Json;
using server.tests.Helpers;
using server.tests.Http;
namespace server.tests.IntegrationTests
namespace server.tests.v1.IntegrationTests
{
public class CharactersControllerIntegrationTests
{
@@ -17,11 +18,7 @@ namespace server.tests.IntegrationTests
public CharactersControllerIntegrationTests()
{
var webAppFactory = new WebApplicationFactory<Program>();
_client = webAppFactory.CreateDefaultClient();
_client.DefaultRequestHeaders.Add("x-api-version", "1");
_client = HttpClientFactory.GetHttpClient(1);
_serializerOptions = new JsonSerializerOptions
{
@@ -51,9 +48,9 @@ namespace server.tests.IntegrationTests
[Fact]
public async Task GetCharactersAsync_SeasonOneCharacters_Returns200StatusCodeWithCharacters()
{
var seasonValue = 1;
var season = 1;
var url = $"{_endpoint}?season={seasonValue}";
var url = $"{_endpoint}?{nameof(season)}={season}";
var response = await _client.GetAsync(url);
@@ -70,16 +67,16 @@ namespace server.tests.IntegrationTests
foreach (var character in characters)
{
character.Seasons.Should().Contain(seasonValue);
character.Seasons.Should().Contain(season);
}
}
[Fact]
public async Task GetCharactersAsync_InvalidSeasonQueryParameter_Returns400StatusCodeWithValidationProblemDetails()
{
var seasonValue = "test";
var season = "test";
var url = $"{_endpoint}?season={seasonValue}";
var url = $"{_endpoint}?{nameof(season)}={season}";
var response = await _client.GetAsync(url);
@@ -98,9 +95,9 @@ namespace server.tests.IntegrationTests
[Fact]
public async Task GetCharactersAsync_NameContainsJason_Returns200StatusCodeWithCharacters()
{
var nameValue = "jason";
var name = "jason";
var url = $"{_endpoint}?name={nameValue}";
var url = $"{_endpoint}?{nameof(name)}={name}";
var response = await _client.GetAsync(url);
@@ -117,16 +114,16 @@ namespace server.tests.IntegrationTests
foreach (var character in characters)
{
character.FullName.ToLower().Should().Contain(nameValue);
character.FullName.ToLower().Should().Contain(name);
}
}
[Fact]
public async Task GetCharactersAsync_ActorNameContainsMandy_Returns200StatusCodeWithCharacters()
{
var actorNameValue = "mandy";
var actorName = "mandy";
var url = $"{_endpoint}?actorname={actorNameValue}";
var url = $"{_endpoint}?{nameof(actorName)}={actorName}";
var response = await _client.GetAsync(url);
@@ -143,7 +140,7 @@ namespace server.tests.IntegrationTests
foreach (var character in characters)
{
character.ActorFullName.ToLower().Should().Contain(actorNameValue);
character.ActorFullName.ToLower().Should().Contain(actorName);
}
}
@@ -0,0 +1,439 @@
using FluentAssertions;
using Microsoft.AspNetCore.Mvc;
using server.Models;
using server.tests.Helpers;
using server.tests.Http;
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.GetHttpClient(1);
_serializerOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
_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,49 @@
using server.tests.Http;
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.GetHttpClient(1);
_serializerOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
_endpoint = "/api/seasons";
}
[Fact]
public async Task GetSeasonsAsync_AllSeasons_Returns200StatusCodeWithSeasons()
{
throw new NotImplementedException();
}
[Fact]
public async Task GetSeasonByNumberAsync_SeasonOne_Returns200StatusCodeWithSeason()
{
throw new NotImplementedException();
}
[Fact]
public async Task GetSeasonByNumberAsync_InvalidSeason_Returns404StatusCode()
{
throw new NotImplementedException();
}
[Fact]
public async Task GetSeasonByNumberAsync_ValidSeasonNumberForNonExistentSeason_Returns404StatusCode()
{
throw new NotImplementedException();
}
}
}
@@ -6,14 +6,14 @@ using server.Models;
using server.Persistence.Repositories;
using System.Net;
namespace server.tests.UnitTests
namespace server.tests.v1.UnitTests
{
public class CharacterControllerUnitTests
public class CharactersControllerUnitTests
{
private readonly Mock<ICharacterRepository> _mockRepo;
private readonly CharactersController _controller;
public CharacterControllerUnitTests()
public CharactersControllerUnitTests()
{
_mockRepo = new Mock<ICharacterRepository>();
_controller = new CharactersController(_mockRepo.Object);
@@ -67,29 +67,6 @@ namespace server.tests.UnitTests
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>();
}
[Fact]
public async Task GetCharacterByIdAsync_ValidCharacterId_Returns200StatusCodeWithCharacter()
{
@@ -112,5 +89,28 @@ namespace server.tests.UnitTests
character.Should().NotBeNull();
character.Should().BeOfType<Character>();
}
[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,49 @@
using Moq;
using server.Controllers.v1;
using server.Persistence.Repositories;
using System.Runtime.CompilerServices;
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()
{
throw new NotImplementedException();
}
[Fact]
public async Task GetSeasonsAsync_RepoThrowsException_Returns500StatusCodeWithProblemDetails()
{
throw new NotImplementedException();
}
[Fact]
public async Task GetSeasonByNumberAsync_ValidSeasonNumber_Returns200StatusCodeWithSeason()
{
throw new NotImplementedException();
}
[Fact]
public async Task GetSeasonByNumberAsync_ValidSeasonNumberForNonExistentSeason_Returns404StatusCodeWithProblemDetails()
{
throw new NotImplementedException();
}
[Fact]
public async Task GetSeasonByNumberAsync_RepoThrowsException_Returns500StatusCodeWithProblemDetails()
{
throw new NotImplementedException();
}
}
}
@@ -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)