Skip to content

Commit

Permalink
traditional tests and more delegate based film routes
Browse files Browse the repository at this point in the history
  • Loading branch information
jchannon committed Jan 7, 2018
1 parent bdf33df commit face3c4
Show file tree
Hide file tree
Showing 7 changed files with 479 additions and 9 deletions.
26 changes: 26 additions & 0 deletions DDDScot.sln
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4. Functional Project", "4.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FunctionalProject", "FunctionalProject\FunctionalProject.csproj", "{A511EF90-1484-45BA-8D8E-2BB733597A84}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E2EE7155-DAB9-4A7F-9D2E-2A38ECCCC566}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{44C1DD68-1371-456C-9541-BCC3CEE8A2BE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1. Tradtional Project Tests", "1. Tradtional Project Tests", "{DD7F5385-6594-4AF5-ADE9-ABC65C2A29BC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TradtionalWebAPI.Tests", "TradtionalWebAPI.Tests\TradtionalWebAPI.Tests.csproj", "{2974A21D-76F8-4248-BF01-E7B5BDA6A6FF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -65,11 +73,29 @@ Global
{A511EF90-1484-45BA-8D8E-2BB733597A84}.Release|x64.Build.0 = Release|Any CPU
{A511EF90-1484-45BA-8D8E-2BB733597A84}.Release|x86.ActiveCfg = Release|Any CPU
{A511EF90-1484-45BA-8D8E-2BB733597A84}.Release|x86.Build.0 = Release|Any CPU
{2974A21D-76F8-4248-BF01-E7B5BDA6A6FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2974A21D-76F8-4248-BF01-E7B5BDA6A6FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2974A21D-76F8-4248-BF01-E7B5BDA6A6FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2974A21D-76F8-4248-BF01-E7B5BDA6A6FF}.Release|Any CPU.Build.0 = Release|Any CPU
{2974A21D-76F8-4248-BF01-E7B5BDA6A6FF}.Debug|x64.ActiveCfg = Debug|Any CPU
{2974A21D-76F8-4248-BF01-E7B5BDA6A6FF}.Debug|x64.Build.0 = Debug|Any CPU
{2974A21D-76F8-4248-BF01-E7B5BDA6A6FF}.Debug|x86.ActiveCfg = Debug|Any CPU
{2974A21D-76F8-4248-BF01-E7B5BDA6A6FF}.Debug|x86.Build.0 = Debug|Any CPU
{2974A21D-76F8-4248-BF01-E7B5BDA6A6FF}.Release|x64.ActiveCfg = Release|Any CPU
{2974A21D-76F8-4248-BF01-E7B5BDA6A6FF}.Release|x64.Build.0 = Release|Any CPU
{2974A21D-76F8-4248-BF01-E7B5BDA6A6FF}.Release|x86.ActiveCfg = Release|Any CPU
{2974A21D-76F8-4248-BF01-E7B5BDA6A6FF}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{626AD192-F5D0-4AE1-AEEC-7B8FE40E927F} = {66D3DCED-78BD-4DB8-8C8D-3A5FA09543C6}
{40EC1455-176C-4B55-A550-E6F54AFD4491} = {48EF8D64-76E9-4E2A-9939-7D50C7E320B8}
{3442E574-7406-4DD0-A28A-96534CE47310} = {892479C5-1CB2-4748-A910-89A57995D73C}
{A511EF90-1484-45BA-8D8E-2BB733597A84} = {345FCBAD-019D-4A9B-B7A3-05A536BECBA4}
{345FCBAD-019D-4A9B-B7A3-05A536BECBA4} = {E2EE7155-DAB9-4A7F-9D2E-2A38ECCCC566}
{892479C5-1CB2-4748-A910-89A57995D73C} = {E2EE7155-DAB9-4A7F-9D2E-2A38ECCCC566}
{48EF8D64-76E9-4E2A-9939-7D50C7E320B8} = {E2EE7155-DAB9-4A7F-9D2E-2A38ECCCC566}
{66D3DCED-78BD-4DB8-8C8D-3A5FA09543C6} = {E2EE7155-DAB9-4A7F-9D2E-2A38ECCCC566}
{DD7F5385-6594-4AF5-ADE9-ABC65C2A29BC} = {44C1DD68-1371-456C-9541-BCC3CEE8A2BE}
{2974A21D-76F8-4248-BF01-E7B5BDA6A6FF} = {DD7F5385-6594-4AF5-ADE9-ABC65C2A29BC}
EndGlobalSection
EndGlobal
29 changes: 29 additions & 0 deletions FunctionalProject/Features/DelegateFilms/FilmsModule.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,47 @@
namespace FunctionalProject.Features.DelegateFilms
{
using System;
using System.Threading.Tasks;
using Botwin;
using Botwin.ModelBinding;
using Botwin.Request;
using Botwin.Response;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Models;

public class FilmsModule : BotwinModule
{
public FilmsModule() : base("/api/films")
{
this.Get("/", this.GetFilms);
this.Get("/{id:int}", this.GetFilmById);
this.Put("/{id:int}", this.UpdateFilm);
}

private async Task UpdateFilm(HttpContext context)
{
var result = context.Request.BindAndValidate<Film>();

if (!result.ValidationResult.IsValid)
{
context.Response.StatusCode = 422;
await context.Response.Negotiate(result.ValidationResult.GetFormattedErrors());
return;
}

try
{
var handler = RouteHandlers.UpdateFilmHandler;

handler(context.GetRouteData().As<int>("id"), result.Data);

context.Response.StatusCode = 204;
}
catch (Exception)
{
context.Response.StatusCode = 403;
}
}

private async Task GetFilms(HttpContext context)
Expand Down
36 changes: 27 additions & 9 deletions FunctionalProject/Features/DelegateFilms/RouteHandlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Generic;
using FunctionalProject.Features.DelegateFilms.ListFilmById;
using FunctionalProject.Features.DelegateFilms.ListFilms;
using FunctionalProject.Features.DelegateFilms.UpdateFilm;
using Models;

public static class RouteHandlers
Expand All @@ -12,6 +13,10 @@ public static class RouteHandlers

private static Func<int, Film> listFilmById;

private static Action<int, Film> updateFilm;

//private static Func<int,Film> getFilmyById = i => new Film { Id = 1, Name = "Pulp Fiction", DirectorId = 1 };

public static Func<IEnumerable<Film>> ListFilmsHandler
{
get => listFilms ?? ListFilmsRoute.Handle;
Expand All @@ -21,17 +26,30 @@ public static Func<IEnumerable<Film>> ListFilmsHandler
public static Func<int, Film> ListFilmBIdHandler
{
get => listFilmById ?? (filmId => ListFilmByIdRoute.Handle(
filmId,
//Write some SQL to get the film
fId => new Film { Id = 1, Name = "Pulp Fiction", DirectorId = 1 },
//Write some SQL to get the director
dirId => new Director { Name = "Steven Spielberg" },
//Write some SQL to get the cast
fId => new[] { new CastMember { Name = "John Travolta" }, new CastMember { Name = "Samuel L Jackson" } }
)
);
filmId,
//Write some SQL to get the film
fId => new Film { Id = 1, Name = "Pulp Fiction", DirectorId = 1 },
//Write some SQL to get the director
dirId => new Director { Name = "Steven Spielberg" },
//Write some SQL to get the cast
fId => new[] { new CastMember { Name = "John Travolta" }, new CastMember { Name = "Samuel L Jackson" } }
)
);

set => listFilmById = value;
}

public static Action<int, Film> UpdateFilmHandler
{
get => updateFilm ?? ((filmId, film) => UpdateFilmRoute.Handle(
filmId,
film,
() => new Random().Next() % 2 == 0,
fId => new Film { Id = 1, Name = "Pulp Fiction", DirectorId = 1 }
)
);

set => updateFilm = value;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace FunctionalProject.Features.DelegateFilms.UpdateFilm
{
using System;
using Models;

public static class UpdateFilmRoute
{
public static void Handle(int id, Film film, Func<bool> validUserQuery, Func<int, Film> listFilmById)
{
if (!validUserQuery())
{
throw new InvalidOperationException();
}

//Do some special MEGA CORP business validation

var existingFilm = listFilmById(id);

existingFilm.Name = film.Name;
existingFilm.Budget = film.Budget;
existingFilm.Language = film.Language;

//Write some SQL to store in db

}
}
}
212 changes: 212 additions & 0 deletions TradtionalWebAPI.Tests/FilmControllerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
namespace TradtionalWebAPI.Tests
{
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using FakeItEasy;
using FluentValidation;
using FluentValidation.AspNetCore;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Models;
using Newtonsoft.Json;
using TraditionalWebAPI.Services;
using Xunit;

public class FilmControllerTests
{

[Fact]
public async Task Should_get_list_of_films()
{
//Given
var client = this.GetClient();

//When
var response = await client.GetAsync("/api/films");
var contents = await response.Content.ReadAsStringAsync();

//Then
Assert.Contains("Goodfellas", contents, StringComparison.OrdinalIgnoreCase);
}

[Fact]
public async Task Should_get_film_by_id()
{
//Given
var client = this.GetClient();

//When
var response = await client.GetAsync("/api/films/1");
var contents = await response.Content.ReadAsStringAsync();

//Then
Assert.Contains("Blade Runner", contents, StringComparison.OrdinalIgnoreCase);
}

[Fact]
public async Task Should_return_404_when_no_film_found_via_get_film_by_id()
{
//Given
var fakeFilmService = A.Fake<IFilmService>();
A.CallTo(() => fakeFilmService.ListFilmById(1)).Returns(null);

var client = this.GetClient(fakeFilmService);

//When
var response = await client.GetAsync("/api/films/1");

//Then
Assert.Equal(404, (int)response.StatusCode);
}

[Fact]
public async Task Should_return_400_on_invalid_data_when_creating_film()
{
//Given
var client = this.GetClient();
var film = new Film { Name = "" };

//When
var response = await client.PostAsync("/api/films", new StringContent(JsonConvert.SerializeObject(film), Encoding.UTF8, "application/json"));

//Then
Assert.Equal(400, (int)response.StatusCode);
}

[Fact]
public async Task Should_return_403_on_invalid_user_when_creating_film()
{
//Given
var fakeFilmService = A.Fake<IFilmService>();
A.CallTo(() => fakeFilmService.CreateFilm(A<Film>.Ignored)).Throws<InvalidOperationException>();

var client = this.GetClient(fakeFilmService);

var film = new Film { Name = "Shrek" };

//When
var response = await client.PostAsync("/api/films", new StringContent(JsonConvert.SerializeObject(film), Encoding.UTF8, "application/json"));

//Then
Assert.Equal(403, (int)response.StatusCode);
}

[Fact]
public async Task Should_return_201_when_creating_film()
{
//Given
var client = this.GetClient();
var film = new Film { Name = "Shrek" };

//When
var response = await client.PostAsync("/api/films", new StringContent(JsonConvert.SerializeObject(film), Encoding.UTF8, "application/json"));

//Then
Assert.Equal(201, (int)response.StatusCode);
}

[Fact]
public async Task Should_return_400_on_invalid_data_when_updating_film()
{
//Given
var client = this.GetClient();
var film = new Film { Name = "" };

//When
var response = await client.PutAsync("/api/films/1", new StringContent(JsonConvert.SerializeObject(film), Encoding.UTF8, "application/json"));

//Then
Assert.Equal(400, (int)response.StatusCode);
}

[Fact]
public async Task Should_return_403_on_invalid_user_when_updating_film()
{
//Given
var fakeFilmService = A.Fake<IFilmService>();
A.CallTo(() => fakeFilmService.UpdateFilm(1, A<Film>.Ignored)).Throws<InvalidOperationException>();

var client = this.GetClient(fakeFilmService);

var film = new Film { Name = "Shrek" };

//When
var response = await client.PutAsync("/api/films/1", new StringContent(JsonConvert.SerializeObject(film), Encoding.UTF8, "application/json"));

//Then
Assert.Equal(403, (int)response.StatusCode);
}

[Fact]
public async Task Should_return_204_when_deleting_film()
{
//Given
var client = this.GetClient();

//When
var response = await client.DeleteAsync("/api/films/1");

//Then
Assert.Equal(204, (int)response.StatusCode);
}

[Fact]
public async Task Should_return_403_on_invalid_user_when_deleting_film()
{
//Given
var fakeFilmService = A.Fake<IFilmService>();
A.CallTo(() => fakeFilmService.DeleteFilm(1)).Throws<InvalidOperationException>();

var client = this.GetClient(fakeFilmService);

//When
var response = await client.DeleteAsync("/api/films/1");

//Then
Assert.Equal(403, (int)response.StatusCode);
}

[Fact]
public async Task Should_return_204_when_updating_film()
{
//Given
var client = this.GetClient();
var film = new Film { Name = "Shrek" };

//When
var response = await client.PutAsync("/api/films/1", new StringContent(JsonConvert.SerializeObject(film), Encoding.UTF8, "application/json"));

//Then
Assert.Equal(204, (int)response.StatusCode);
}

private HttpClient GetClient(IFilmService filmService = null)
{
if (filmService == null)
{
filmService = A.Fake<IFilmService>();
A.CallTo(() => filmService.ListFilms()).Returns(new[] { new Film { Name = "Goodfellas" } });
A.CallTo(() => filmService.ListFilmById(1)).Returns(new Film { Name = "Blade Runner" });
}

var server = new TestServer(WebHost.CreateDefaultBuilder()
.Configure(app => { app.UseMvc(); })
.ConfigureServices(services =>
{
services.AddSingleton<IFilmService>(filmService);

services.AddTransient<IValidator<Film>, FilmValidator>();

services.AddMvc().AddFluentValidation();
})
);

return server.CreateClient();
}
}
}
Loading

0 comments on commit face3c4

Please sign in to comment.