From 38ae9a460055511b79ffbda7ad68e07dada3dbd3 Mon Sep 17 00:00:00 2001 From: Carl-Hugo Marcotte Date: Fri, 25 Aug 2017 01:49:50 -0400 Subject: [PATCH 01/11] Initial split of the part 8 code --- .../ForEvolve.Blog.Samples.NinjaApi.sln | 0 10. NinjaApi - NinjaRepository/README.md | 4 + .../Controllers/ClansController.cs | 0 .../Controllers/NinjaController.cs | 0 .../Exceptions/ClanNotFoundException.cs | 0 .../Exceptions/NinjaApiException.cs | 0 .../Exceptions/NinjaNotFoundException.cs | 0 .../ForEvolve.Blog.Samples.NinjaApi.csproj | 0 .../Mappers/IMapper.cs | 0 .../NinjaEntityEnumerableToNinjaMapper.cs | 0 .../Mappers/NinjaEntityToNinjaMapper.cs | 0 .../Mappers/NinjaToNinjaEntityMapper.cs | 0 .../Models/Clan.cs | 0 .../Models/Ninja.cs | 0 .../Models/NinjaEntity.cs | 0 .../Program.cs | 25 ++ .../Properties/launchSettings.json | 0 .../Repositories/ClanRepository.cs | 0 .../Repositories/IClanRepository.cs | 0 .../Repositories/INinjaRepository.cs | 18 + .../Services/ClanService.cs | 0 .../Services/IClanService.cs | 0 .../Services/INinjaMappingService.cs | 0 .../Services/INinjaService.cs | 0 .../Services/NinjaMappingService.cs | 0 .../Services/NinjaService.cs | 0 .../Startup.cs | 39 +++ .../appsettings.Development.json | 10 + .../appsettings.json | 15 + .../BaseHttpTest.cs | 59 ++++ .../ClansControllerTest.cs | 0 ...g.Samples.NinjaApi.IntegrationTests.csproj | 20 ++ .../StartupTest.cs | 34 ++ .../Controllers/ClansControllerTest.cs | 0 .../Controllers/NinjaControllerTest.cs | 0 ...rEvolve.Blog.Samples.NinjaApi.Tests.csproj | 0 .../NinjaEntityEnumerableToNinjaMapperTest.cs | 0 .../Mappers/NinjaEntityToNinjaMapperTest.cs | 0 .../Mappers/NinjaToNinjaEntityMapperTest.cs | 0 .../Repositories/ClanRepositoryTest.cs | 0 .../Services/ClanServiceTest.cs | 0 .../Services/NinjaMappingServiceTest.cs | 0 .../Services/NinjaServiceTest.cs | 0 .../ForEvolve.Blog.Samples.NinjaApi.sln | 46 +++ 11. NinjaApi - IntegrationTesting/README.md | 4 + .../Controllers/ClansController.cs | 29 ++ .../Controllers/NinjaController.cs | 117 +++++++ .../Exceptions/ClanNotFoundException.cs | 17 + .../Exceptions/NinjaApiException.cs | 27 ++ .../Exceptions/NinjaNotFoundException.cs | 17 + .../ForEvolve.Blog.Samples.NinjaApi.csproj | 18 + .../Mappers/IMapper.cs | 7 + .../NinjaEntityEnumerableToNinjaMapper.cs | 30 ++ .../Mappers/NinjaEntityToNinjaMapper.cs | 19 ++ .../Mappers/NinjaToNinjaEntityMapper.cs | 19 ++ .../Models/Clan.cs | 12 + .../Models/Ninja.cs | 15 + .../Models/NinjaEntity.cs | 14 + .../Program.cs | 0 .../Properties/launchSettings.json | 29 ++ .../Repositories/ClanRepository.cs | 45 +++ .../Repositories/IClanRepository.cs | 16 + .../Repositories/INinjaRepository.cs | 0 .../Repositories/NinjaRepository.cs | 0 .../Services/ClanService.cs | 49 +++ .../Services/IClanService.cs | 17 + .../Services/INinjaMappingService.cs | 13 + .../Services/INinjaService.cs | 17 + .../Services/NinjaMappingService.cs | 40 +++ .../Services/NinjaService.cs | 78 +++++ .../Startup.cs | 0 .../appsettings.Development.json | 0 .../appsettings.json | 0 .../BaseHttpTest.cs | 0 .../ClansControllerTest.cs | 51 +++ ...g.Samples.NinjaApi.IntegrationTests.csproj | 0 .../NinjaControllerTest.cs | 0 .../NinjaEntityTableStorageRepositoryFake.cs | 0 .../StartupTest.cs | 0 .../appsettings.json | 0 .../Controllers/ClansControllerTest.cs | 47 +++ .../Controllers/NinjaControllerTest.cs | 270 +++++++++++++++ ...rEvolve.Blog.Samples.NinjaApi.Tests.csproj | 22 ++ .../NinjaEntityEnumerableToNinjaMapperTest.cs | 45 +++ .../Mappers/NinjaEntityToNinjaMapperTest.cs | 41 +++ .../Mappers/NinjaToNinjaEntityMapperTest.cs | 43 +++ .../Repositories/ClanRepositoryTest.cs | 103 ++++++ .../Repositories/NinjaRepositoryTest.cs | 0 .../Services/ClanServiceTest.cs | 149 ++++++++ .../Services/NinjaMappingServiceTest.cs | 81 +++++ .../Services/NinjaServiceTest.cs | 323 ++++++++++++++++++ .../TestDataFactory.cs | 0 .../ForEvolve.Blog.Samples.NinjaApi.sln | 46 +++ 8. NinjaApi - NinjaEntity/README.md | 4 + .../Controllers/ClansController.cs | 29 ++ .../Controllers/NinjaController.cs | 117 +++++++ .../Exceptions/ClanNotFoundException.cs | 17 + .../Exceptions/NinjaApiException.cs | 27 ++ .../Exceptions/NinjaNotFoundException.cs | 17 + .../ForEvolve.Blog.Samples.NinjaApi.csproj | 18 + .../Models/Clan.cs | 12 + .../Models/Ninja.cs | 15 + .../Models/NinjaEntity.cs | 14 + .../Program.cs | 25 ++ .../Properties/launchSettings.json | 29 ++ .../Repositories/ClanRepository.cs | 45 +++ .../Repositories/IClanRepository.cs | 16 + .../Repositories/INinjaRepository.cs | 18 + .../Services/ClanService.cs | 49 +++ .../Services/IClanService.cs | 17 + .../Services/INinjaService.cs | 17 + .../Services/NinjaService.cs | 78 +++++ .../Startup.cs | 39 +++ .../appsettings.Development.json | 10 + .../appsettings.json | 15 + .../BaseHttpTest.cs | 59 ++++ .../ClansControllerTest.cs | 51 +++ ...g.Samples.NinjaApi.IntegrationTests.csproj | 20 ++ .../StartupTest.cs | 34 ++ .../Controllers/ClansControllerTest.cs | 47 +++ .../Controllers/NinjaControllerTest.cs | 270 +++++++++++++++ ...rEvolve.Blog.Samples.NinjaApi.Tests.csproj | 22 ++ .../Repositories/ClanRepositoryTest.cs | 103 ++++++ .../Services/ClanServiceTest.cs | 149 ++++++++ .../Services/NinjaServiceTest.cs | 323 ++++++++++++++++++ 8. NinjaApi - NinjaRepository/README.md | 4 - .../ForEvolve.Blog.Samples.NinjaApi.sln | 46 +++ 9. NinjaApi - NinjaMappingService/README.md | 4 + .../Controllers/ClansController.cs | 29 ++ .../Controllers/NinjaController.cs | 117 +++++++ .../Exceptions/ClanNotFoundException.cs | 17 + .../Exceptions/NinjaApiException.cs | 27 ++ .../Exceptions/NinjaNotFoundException.cs | 17 + .../ForEvolve.Blog.Samples.NinjaApi.csproj | 18 + .../Mappers/IMapper.cs | 7 + .../NinjaEntityEnumerableToNinjaMapper.cs | 30 ++ .../Mappers/NinjaEntityToNinjaMapper.cs | 19 ++ .../Mappers/NinjaToNinjaEntityMapper.cs | 19 ++ .../Models/Clan.cs | 12 + .../Models/Ninja.cs | 15 + .../Models/NinjaEntity.cs | 14 + .../Program.cs | 25 ++ .../Properties/launchSettings.json | 29 ++ .../Repositories/ClanRepository.cs | 45 +++ .../Repositories/IClanRepository.cs | 16 + .../Repositories/INinjaRepository.cs | 18 + .../Services/ClanService.cs | 49 +++ .../Services/IClanService.cs | 17 + .../Services/INinjaMappingService.cs | 13 + .../Services/INinjaService.cs | 17 + .../Services/NinjaMappingService.cs | 40 +++ .../Services/NinjaService.cs | 78 +++++ .../Startup.cs | 39 +++ .../appsettings.Development.json | 10 + .../appsettings.json | 15 + .../BaseHttpTest.cs | 59 ++++ .../ClansControllerTest.cs | 51 +++ ...g.Samples.NinjaApi.IntegrationTests.csproj | 20 ++ .../StartupTest.cs | 34 ++ .../Controllers/ClansControllerTest.cs | 47 +++ .../Controllers/NinjaControllerTest.cs | 270 +++++++++++++++ ...rEvolve.Blog.Samples.NinjaApi.Tests.csproj | 22 ++ .../NinjaEntityEnumerableToNinjaMapperTest.cs | 45 +++ .../Mappers/NinjaEntityToNinjaMapperTest.cs | 41 +++ .../Mappers/NinjaToNinjaEntityMapperTest.cs | 43 +++ .../Repositories/ClanRepositoryTest.cs | 103 ++++++ .../Services/ClanServiceTest.cs | 149 ++++++++ .../Services/NinjaMappingServiceTest.cs | 81 +++++ .../Services/NinjaServiceTest.cs | 323 ++++++++++++++++++ 169 files changed, 5936 insertions(+), 4 deletions(-) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/ForEvolve.Blog.Samples.NinjaApi.sln (100%) create mode 100644 10. NinjaApi - NinjaRepository/README.md rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/ClansController.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/NinjaController.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/ClanNotFoundException.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaApiException.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaNotFoundException.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/IMapper.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityToNinjaMapper.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaToNinjaEntityMapper.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Models/Clan.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Models/Ninja.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Models/NinjaEntity.cs (100%) create mode 100644 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Program.cs rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Properties/launchSettings.json (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/ClanRepository.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/IClanRepository.cs (100%) create mode 100644 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/INinjaRepository.cs rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Services/ClanService.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Services/IClanService.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaMappingService.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaService.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaMappingService.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaService.cs (100%) create mode 100644 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs create mode 100644 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.Development.json create mode 100644 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.json create mode 100644 10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/BaseHttpTest.cs rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ClansControllerTest.cs (100%) create mode 100644 10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj create mode 100644 10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/ClansControllerTest.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/NinjaControllerTest.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/test/ForEvolve.Blog.Samples.NinjaApi.Tests/ForEvolve.Blog.Samples.NinjaApi.Tests.csproj (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityToNinjaMapperTest.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaToNinjaEntityMapperTest.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/ClanRepositoryTest.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/ClanServiceTest.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaMappingServiceTest.cs (100%) rename {8. NinjaApi - NinjaRepository => 10. NinjaApi - NinjaRepository}/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaServiceTest.cs (100%) create mode 100644 11. NinjaApi - IntegrationTesting/ForEvolve.Blog.Samples.NinjaApi.sln create mode 100644 11. NinjaApi - IntegrationTesting/README.md create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/ClansController.cs create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/NinjaController.cs create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/ClanNotFoundException.cs create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaApiException.cs create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaNotFoundException.cs create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/IMapper.cs create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityToNinjaMapper.cs create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaToNinjaEntityMapper.cs create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Models/Clan.cs create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Models/Ninja.cs create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Models/NinjaEntity.cs rename {8. NinjaApi - NinjaRepository => 11. NinjaApi - IntegrationTesting}/src/ForEvolve.Blog.Samples.NinjaApi/Program.cs (100%) create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Properties/launchSettings.json create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/ClanRepository.cs create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/IClanRepository.cs rename {8. NinjaApi - NinjaRepository => 11. NinjaApi - IntegrationTesting}/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/INinjaRepository.cs (100%) rename {8. NinjaApi - NinjaRepository => 11. NinjaApi - IntegrationTesting}/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/NinjaRepository.cs (100%) create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/ClanService.cs create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/IClanService.cs create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaMappingService.cs create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaService.cs create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaMappingService.cs create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaService.cs rename {8. NinjaApi - NinjaRepository => 11. NinjaApi - IntegrationTesting}/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs (100%) rename {8. NinjaApi - NinjaRepository => 11. NinjaApi - IntegrationTesting}/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.Development.json (100%) rename {8. NinjaApi - NinjaRepository => 11. NinjaApi - IntegrationTesting}/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.json (100%) rename {8. NinjaApi - NinjaRepository => 11. NinjaApi - IntegrationTesting}/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/BaseHttpTest.cs (100%) create mode 100644 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ClansControllerTest.cs rename {8. NinjaApi - NinjaRepository => 11. NinjaApi - IntegrationTesting}/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj (100%) rename {8. NinjaApi - NinjaRepository => 11. NinjaApi - IntegrationTesting}/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaControllerTest.cs (100%) rename {8. NinjaApi - NinjaRepository => 11. NinjaApi - IntegrationTesting}/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaEntityTableStorageRepositoryFake.cs (100%) rename {8. NinjaApi - NinjaRepository => 11. NinjaApi - IntegrationTesting}/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs (100%) rename {8. NinjaApi - NinjaRepository => 11. NinjaApi - IntegrationTesting}/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/appsettings.json (100%) create mode 100644 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/ClansControllerTest.cs create mode 100644 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/NinjaControllerTest.cs create mode 100644 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/ForEvolve.Blog.Samples.NinjaApi.Tests.csproj create mode 100644 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs create mode 100644 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityToNinjaMapperTest.cs create mode 100644 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaToNinjaEntityMapperTest.cs create mode 100644 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/ClanRepositoryTest.cs rename {8. NinjaApi - NinjaRepository => 11. NinjaApi - IntegrationTesting}/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/NinjaRepositoryTest.cs (100%) create mode 100644 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/ClanServiceTest.cs create mode 100644 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaMappingServiceTest.cs create mode 100644 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaServiceTest.cs rename {8. NinjaApi - NinjaRepository => 11. NinjaApi - IntegrationTesting}/test/ForEvolve.Blog.Samples.NinjaApi.Tests/TestDataFactory.cs (100%) create mode 100644 8. NinjaApi - NinjaEntity/ForEvolve.Blog.Samples.NinjaApi.sln create mode 100644 8. NinjaApi - NinjaEntity/README.md create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/ClansController.cs create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/NinjaController.cs create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/ClanNotFoundException.cs create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaApiException.cs create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaNotFoundException.cs create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Models/Clan.cs create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Models/Ninja.cs create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Models/NinjaEntity.cs create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Program.cs create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Properties/launchSettings.json create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/ClanRepository.cs create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/IClanRepository.cs create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/INinjaRepository.cs create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Services/ClanService.cs create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Services/IClanService.cs create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaService.cs create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaService.cs create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.Development.json create mode 100644 8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.json create mode 100644 8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/BaseHttpTest.cs create mode 100644 8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ClansControllerTest.cs create mode 100644 8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj create mode 100644 8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs create mode 100644 8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/ClansControllerTest.cs create mode 100644 8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/NinjaControllerTest.cs create mode 100644 8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/ForEvolve.Blog.Samples.NinjaApi.Tests.csproj create mode 100644 8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/ClanRepositoryTest.cs create mode 100644 8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/ClanServiceTest.cs create mode 100644 8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaServiceTest.cs delete mode 100644 8. NinjaApi - NinjaRepository/README.md create mode 100644 9. NinjaApi - NinjaMappingService/ForEvolve.Blog.Samples.NinjaApi.sln create mode 100644 9. NinjaApi - NinjaMappingService/README.md create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/ClansController.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/NinjaController.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/ClanNotFoundException.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaApiException.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaNotFoundException.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/IMapper.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityToNinjaMapper.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaToNinjaEntityMapper.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Models/Clan.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Models/Ninja.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Models/NinjaEntity.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Program.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Properties/launchSettings.json create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/ClanRepository.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/IClanRepository.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/INinjaRepository.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/ClanService.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/IClanService.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaMappingService.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaService.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaMappingService.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaService.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.Development.json create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.json create mode 100644 9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/BaseHttpTest.cs create mode 100644 9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ClansControllerTest.cs create mode 100644 9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj create mode 100644 9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs create mode 100644 9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/ClansControllerTest.cs create mode 100644 9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/NinjaControllerTest.cs create mode 100644 9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/ForEvolve.Blog.Samples.NinjaApi.Tests.csproj create mode 100644 9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs create mode 100644 9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityToNinjaMapperTest.cs create mode 100644 9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaToNinjaEntityMapperTest.cs create mode 100644 9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/ClanRepositoryTest.cs create mode 100644 9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/ClanServiceTest.cs create mode 100644 9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaMappingServiceTest.cs create mode 100644 9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaServiceTest.cs diff --git a/8. NinjaApi - NinjaRepository/ForEvolve.Blog.Samples.NinjaApi.sln b/10. NinjaApi - NinjaRepository/ForEvolve.Blog.Samples.NinjaApi.sln similarity index 100% rename from 8. NinjaApi - NinjaRepository/ForEvolve.Blog.Samples.NinjaApi.sln rename to 10. NinjaApi - NinjaRepository/ForEvolve.Blog.Samples.NinjaApi.sln diff --git a/10. NinjaApi - NinjaRepository/README.md b/10. NinjaApi - NinjaRepository/README.md new file mode 100644 index 0000000..d362674 --- /dev/null +++ b/10. NinjaApi - NinjaRepository/README.md @@ -0,0 +1,4 @@ +# Dependency Injection +This project contains the code sample of the +[Design Patterns: Asp.Net Core Web API, services, and repositories | Part 10: the NinjaRepository and the ForEvolve.Azure](http://www.forevolve.com/en/articles/2017/09/13/design-patterns-web-api-service-and-repository-part-10/) +article. \ No newline at end of file diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/ClansController.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/ClansController.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/ClansController.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/ClansController.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/NinjaController.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/NinjaController.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/NinjaController.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/NinjaController.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/ClanNotFoundException.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/ClanNotFoundException.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/ClanNotFoundException.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/ClanNotFoundException.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaApiException.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaApiException.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaApiException.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaApiException.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaNotFoundException.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaNotFoundException.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaNotFoundException.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaNotFoundException.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/IMapper.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/IMapper.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/IMapper.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/IMapper.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityToNinjaMapper.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityToNinjaMapper.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityToNinjaMapper.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityToNinjaMapper.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaToNinjaEntityMapper.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaToNinjaEntityMapper.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaToNinjaEntityMapper.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaToNinjaEntityMapper.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Models/Clan.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Models/Clan.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Models/Clan.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Models/Clan.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Models/Ninja.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Models/Ninja.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Models/Ninja.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Models/Ninja.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Models/NinjaEntity.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Models/NinjaEntity.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Models/NinjaEntity.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Models/NinjaEntity.cs diff --git a/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Program.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Program.cs new file mode 100644 index 0000000..88c9273 --- /dev/null +++ b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Program.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace ForEvolve.Blog.Samples.NinjaApi +{ + public class Program + { + public static void Main(string[] args) + { + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup() + .Build(); + } +} diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Properties/launchSettings.json b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Properties/launchSettings.json similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Properties/launchSettings.json rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Properties/launchSettings.json diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/ClanRepository.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/ClanRepository.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/ClanRepository.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/ClanRepository.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/IClanRepository.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/IClanRepository.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/IClanRepository.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/IClanRepository.cs diff --git a/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/INinjaRepository.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/INinjaRepository.cs new file mode 100644 index 0000000..0075b92 --- /dev/null +++ b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/INinjaRepository.cs @@ -0,0 +1,18 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Repositories +{ + public interface INinjaRepository + { + Task> ReadAllAsync(); + Task> ReadAllInClanAsync(string clanName); + Task ReadOneAsync(string clanName, string ninjaKey); + Task CreateAsync(Ninja ninja); + Task UpdateAsync(Ninja ninja); + Task DeleteAsync(string clanName, string ninjaKey); + } +} diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/ClanService.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/ClanService.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/ClanService.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/ClanService.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/IClanService.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/IClanService.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/IClanService.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/IClanService.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaMappingService.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaMappingService.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaMappingService.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaMappingService.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaService.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaService.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaService.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaService.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaMappingService.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaMappingService.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaMappingService.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaMappingService.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaService.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaService.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaService.cs rename to 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaService.cs diff --git a/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs new file mode 100644 index 0000000..dcfa445 --- /dev/null +++ b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.DependencyInjection.Extensions; +using ForEvolve.Blog.Samples.NinjaApi.Services; +using ForEvolve.Blog.Samples.NinjaApi.Repositories; +using ForEvolve.Blog.Samples.NinjaApi.Models; + +namespace ForEvolve.Blog.Samples.NinjaApi +{ + public class Startup + { + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton>(new Clan[]{ + new Clan { Name = "Iga" }, + new Clan { Name = "Kōga" }, + }); + services.AddMvc(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + app.ApplicationServices.GetService(); + app.UseMvc(); + } + } +} diff --git a/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.Development.json b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.Development.json new file mode 100644 index 0000000..fa8ce71 --- /dev/null +++ b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.Development.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.json b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.json new file mode 100644 index 0000000..26bb0ac --- /dev/null +++ b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.json @@ -0,0 +1,15 @@ +{ + "Logging": { + "IncludeScopes": false, + "Debug": { + "LogLevel": { + "Default": "Warning" + } + }, + "Console": { + "LogLevel": { + "Default": "Warning" + } + } + } +} diff --git a/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/BaseHttpTest.cs b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/BaseHttpTest.cs new file mode 100644 index 0000000..e314434 --- /dev/null +++ b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/BaseHttpTest.cs @@ -0,0 +1,59 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Text; + +namespace ForEvolve.Blog.Samples.NinjaApi.IntegrationTests +{ + public abstract class BaseHttpTest : IDisposable + { + protected TestServer Server { get; } + protected HttpClient Client { get; } + + protected virtual Uri BaseAddress => new Uri("http://localhost"); + protected virtual string Environment => "Development"; + + public BaseHttpTest() + { + var builder = new WebHostBuilder() + .UseEnvironment(Environment) + .ConfigureServices(ConfigureServices) + .UseStartup(); + + Server = new TestServer(builder); + Client = Server.CreateClient(); + Client.BaseAddress = BaseAddress; + } + + protected virtual void ConfigureServices(IServiceCollection services) + { + } + + #region IDisposable Support + + private bool disposedValue = false; + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + Client.Dispose(); + Server.Dispose(); + } + disposedValue = true; + } + } + + public void Dispose() + { + Dispose(true); + } + + #endregion + } +} diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ClansControllerTest.cs b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ClansControllerTest.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ClansControllerTest.cs rename to 10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ClansControllerTest.cs diff --git a/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj new file mode 100644 index 0000000..8ad286b --- /dev/null +++ b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp2.0 + + false + + + + + + + + + + + + + + diff --git a/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs new file mode 100644 index 0000000..637653f --- /dev/null +++ b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs @@ -0,0 +1,34 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; +using Microsoft.Extensions.DependencyInjection; +using System.Linq; + +namespace ForEvolve.Blog.Samples.NinjaApi.IntegrationTests +{ + public class StartupTest : BaseHttpTest + { + public class ServiceProvider : StartupTest + { + [Fact] + public void Should_return_both_Iga_and_Kōga_clans() + { + // Arrange + var serviceProvider = Server.Host.Services; + + // Act + var clans = serviceProvider.GetService>(); + + // Assert + Assert.NotNull(clans); + Assert.Equal(2, clans.Count()); + Assert.Collection(clans, + clan => Assert.Equal("Iga", clan.Name), + clan => Assert.Equal("Kōga", clan.Name) + ); + } + } + } +} diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/ClansControllerTest.cs b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/ClansControllerTest.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/ClansControllerTest.cs rename to 10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/ClansControllerTest.cs diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/NinjaControllerTest.cs b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/NinjaControllerTest.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/NinjaControllerTest.cs rename to 10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/NinjaControllerTest.cs diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/ForEvolve.Blog.Samples.NinjaApi.Tests.csproj b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/ForEvolve.Blog.Samples.NinjaApi.Tests.csproj similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/ForEvolve.Blog.Samples.NinjaApi.Tests.csproj rename to 10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/ForEvolve.Blog.Samples.NinjaApi.Tests.csproj diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs rename to 10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityToNinjaMapperTest.cs b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityToNinjaMapperTest.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityToNinjaMapperTest.cs rename to 10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityToNinjaMapperTest.cs diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaToNinjaEntityMapperTest.cs b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaToNinjaEntityMapperTest.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaToNinjaEntityMapperTest.cs rename to 10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaToNinjaEntityMapperTest.cs diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/ClanRepositoryTest.cs b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/ClanRepositoryTest.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/ClanRepositoryTest.cs rename to 10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/ClanRepositoryTest.cs diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/ClanServiceTest.cs b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/ClanServiceTest.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/ClanServiceTest.cs rename to 10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/ClanServiceTest.cs diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaMappingServiceTest.cs b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaMappingServiceTest.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaMappingServiceTest.cs rename to 10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaMappingServiceTest.cs diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaServiceTest.cs b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaServiceTest.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaServiceTest.cs rename to 10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaServiceTest.cs diff --git a/11. NinjaApi - IntegrationTesting/ForEvolve.Blog.Samples.NinjaApi.sln b/11. NinjaApi - IntegrationTesting/ForEvolve.Blog.Samples.NinjaApi.sln new file mode 100644 index 0000000..48f81a9 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/ForEvolve.Blog.Samples.NinjaApi.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26711.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{23BF447F-B872-4D4F-8F28-D443072AE93E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{2F55FE43-6EA6-4A7E-B70B-2E8267478F29}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ForEvolve.Blog.Samples.NinjaApi", "src\ForEvolve.Blog.Samples.NinjaApi\ForEvolve.Blog.Samples.NinjaApi.csproj", "{DD219D97-6BF6-4EE5-9E35-13185F4FA261}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ForEvolve.Blog.Samples.NinjaApi.Tests", "test\ForEvolve.Blog.Samples.NinjaApi.Tests\ForEvolve.Blog.Samples.NinjaApi.Tests.csproj", "{6705EB4C-3DF6-4385-AEAB-3EE2FE074E05}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ForEvolve.Blog.Samples.NinjaApi.IntegrationTests", "test\ForEvolve.Blog.Samples.NinjaApi.IntegrationTests\ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj", "{89C4A3D5-7272-4EC7-AC91-89ED8C1D00EA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DD219D97-6BF6-4EE5-9E35-13185F4FA261}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD219D97-6BF6-4EE5-9E35-13185F4FA261}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD219D97-6BF6-4EE5-9E35-13185F4FA261}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DD219D97-6BF6-4EE5-9E35-13185F4FA261}.Release|Any CPU.Build.0 = Release|Any CPU + {6705EB4C-3DF6-4385-AEAB-3EE2FE074E05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6705EB4C-3DF6-4385-AEAB-3EE2FE074E05}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6705EB4C-3DF6-4385-AEAB-3EE2FE074E05}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6705EB4C-3DF6-4385-AEAB-3EE2FE074E05}.Release|Any CPU.Build.0 = Release|Any CPU + {89C4A3D5-7272-4EC7-AC91-89ED8C1D00EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {89C4A3D5-7272-4EC7-AC91-89ED8C1D00EA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {89C4A3D5-7272-4EC7-AC91-89ED8C1D00EA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {89C4A3D5-7272-4EC7-AC91-89ED8C1D00EA}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {DD219D97-6BF6-4EE5-9E35-13185F4FA261} = {23BF447F-B872-4D4F-8F28-D443072AE93E} + {6705EB4C-3DF6-4385-AEAB-3EE2FE074E05} = {2F55FE43-6EA6-4A7E-B70B-2E8267478F29} + {89C4A3D5-7272-4EC7-AC91-89ED8C1D00EA} = {2F55FE43-6EA6-4A7E-B70B-2E8267478F29} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {47DBF882-4F3A-4C9F-95CC-1286279CC35B} + EndGlobalSection +EndGlobal diff --git a/11. NinjaApi - IntegrationTesting/README.md b/11. NinjaApi - IntegrationTesting/README.md new file mode 100644 index 0000000..e9035b8 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/README.md @@ -0,0 +1,4 @@ +# Dependency Injection +This project contains the code sample of the +[Design Patterns: Asp.Net Core Web API, services, and repositories | Part 11: Integration testing](http://www.forevolve.com/en/articles/2017/09/18/design-patterns-web-api-service-and-repository-part-11/) +article. \ No newline at end of file diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/ClansController.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/ClansController.cs new file mode 100644 index 0000000..4e3d49d --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/ClansController.cs @@ -0,0 +1,29 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Services; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Controllers +{ + [Route("v1/[controller]")] + public class ClansController : Controller + { + private readonly IClanService _clanService; + + public ClansController(IClanService clanService) + { + _clanService = clanService ?? throw new ArgumentNullException(nameof(clanService)); + } + + [HttpGet] + [ProducesResponseType(typeof(IEnumerable), 200)] + public async Task ReadAllAsync() + { + var allClans = await _clanService.ReadAllAsync(); + return Ok(allClans); + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/NinjaController.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/NinjaController.cs new file mode 100644 index 0000000..7f6d7eb --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/NinjaController.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using ForEvolve.Blog.Samples.NinjaApi.Models; +using Microsoft.AspNetCore.Http; +using ForEvolve.Blog.Samples.NinjaApi.Services; + +namespace ForEvolve.Blog.Samples.NinjaApi.Controllers +{ + [Route("v1/[controller]")] + public class NinjaController : Controller + { + private readonly INinjaService _ninjaService; + public NinjaController(INinjaService ninjaService) + { + _ninjaService = ninjaService ?? throw new ArgumentNullException(nameof(ninjaService)); + } + + [HttpGet] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + public async Task ReadAllAsync() + { + var allNinja = await _ninjaService.ReadAllAsync(); + return Ok(allNinja); + } + + [HttpGet("{clan}")] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task ReadAllInClanAsync(string clan) + { + try + { + var clanNinja = await _ninjaService.ReadAllInClanAsync(clan); + return Ok(clanNinja); + } + catch (ClanNotFoundException) + { + return NotFound(); + } + } + + [HttpGet("{clan}/{key}")] + [ProducesResponseType(typeof(Ninja), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task ReadOneAsync(string clan, string key) + { + try + { + var ninja = await _ninjaService.ReadOneAsync(clan, key); + return Ok(ninja); + } + catch (NinjaNotFoundException) + { + return NotFound(); + } + } + + [HttpPost] + [ProducesResponseType(typeof(Ninja), StatusCodes.Status201Created)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task CreateAsync([FromBody]Ninja ninja) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + var createdNinja = await _ninjaService.CreateAsync(ninja); + return CreatedAtAction( + nameof(ReadOneAsync), + new { clan = createdNinja.Clan.Name, key = createdNinja.Key }, + createdNinja + ); + } + + [HttpPut] + [ProducesResponseType(typeof(Ninja), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task UpdateAsync([FromBody]Ninja ninja) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + try + { + var updatedNinja = await _ninjaService.UpdateAsync(ninja); + return Ok(updatedNinja); + } + catch (NinjaNotFoundException) + { + return NotFound(); + } + } + + [HttpDelete("{clan}/{key}")] + [ProducesResponseType(typeof(Ninja), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task DeleteAsync(string clan, string key) + { + try + { + var deletedNinja = await _ninjaService.DeleteAsync(clan, key); + return Ok(deletedNinja); + } + catch (NinjaNotFoundException) + { + return NotFound(); + } + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/ClanNotFoundException.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/ClanNotFoundException.cs new file mode 100644 index 0000000..7d55c95 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/ClanNotFoundException.cs @@ -0,0 +1,17 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; + +namespace ForEvolve.Blog.Samples.NinjaApi +{ + public class ClanNotFoundException : NinjaApiException + { + public ClanNotFoundException(Clan clan) + : this(clan.Name) + { + } + + public ClanNotFoundException(string clanName) + : base($"Clan {clanName} was not found.") + { + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaApiException.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaApiException.cs new file mode 100644 index 0000000..ff81d64 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaApiException.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi +{ + public class NinjaApiException : Exception + { + public NinjaApiException() + { + } + + public NinjaApiException(string message) : base(message) + { + } + + public NinjaApiException(string message, Exception innerException) : base(message, innerException) + { + } + + protected NinjaApiException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaNotFoundException.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaNotFoundException.cs new file mode 100644 index 0000000..54c1d8d --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaNotFoundException.cs @@ -0,0 +1,17 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; + +namespace ForEvolve.Blog.Samples.NinjaApi +{ + public class NinjaNotFoundException : NinjaApiException + { + public NinjaNotFoundException(Ninja ninja) + : base($"Ninja {ninja.Name} ({ninja.Key}) of clan {ninja.Clan.Name} was not found.") + { + } + + public NinjaNotFoundException(string clanName, string ninjaKey) + : base($"Ninja {ninjaKey} of clan {clanName} was not found.") + { + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj new file mode 100644 index 0000000..4c0cd14 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj @@ -0,0 +1,18 @@ + + + + netcoreapp2.0 + aspnet-ForEvolve.Blog.Samples.NinjaApi-F62B525A-ACF4-4C7C-BF23-1EB0F434DDE5 + Full + + + + + + + + + + + + diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/IMapper.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/IMapper.cs new file mode 100644 index 0000000..2628ecb --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/IMapper.cs @@ -0,0 +1,7 @@ +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public interface IMapper + { + TDestination Map(TSource entity); + } +} diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs new file mode 100644 index 0000000..138aac7 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs @@ -0,0 +1,30 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public class NinjaEntityEnumerableToNinjaMapper : IMapper, IEnumerable> + { + private readonly IMapper _ninjaEntityToNinjaMapper; + + public NinjaEntityEnumerableToNinjaMapper(IMapper ninjaEntityToNinjaMapper) + { + _ninjaEntityToNinjaMapper = ninjaEntityToNinjaMapper ?? throw new ArgumentNullException(nameof(ninjaEntityToNinjaMapper)); + } + + public IEnumerable Map(IEnumerable entities) + { + var count = entities.Count(); + var all = new Ninja[count]; + for (int i = 0; i < count; i++) + { + var entity = entities.ElementAt(i); + var ninja = _ninjaEntityToNinjaMapper.Map(entity); + all[i] = ninja; + } + return all; + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityToNinjaMapper.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityToNinjaMapper.cs new file mode 100644 index 0000000..745a6d9 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityToNinjaMapper.cs @@ -0,0 +1,19 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; + +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public class NinjaEntityToNinjaMapper : IMapper + { + public Ninja Map(NinjaEntity entity) + { + var ninja = new Ninja + { + Key = entity.RowKey, + Clan = new Clan { Name = entity.PartitionKey }, + Level = entity.Level, + Name = entity.Name + }; + return ninja; + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaToNinjaEntityMapper.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaToNinjaEntityMapper.cs new file mode 100644 index 0000000..a4546f4 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaToNinjaEntityMapper.cs @@ -0,0 +1,19 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; + +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public class NinjaToNinjaEntityMapper : IMapper + { + public NinjaEntity Map(Ninja ninja) + { + var entity = new NinjaEntity + { + PartitionKey = ninja.Clan.Name, + RowKey = ninja.Key, + Name = ninja.Name, + Level = ninja.Level + }; + return entity; + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Models/Clan.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Models/Clan.cs new file mode 100644 index 0000000..7b7c615 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Models/Clan.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Models +{ + public class Clan + { + public string Name { get; set; } + } +} diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Models/Ninja.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Models/Ninja.cs new file mode 100644 index 0000000..110e285 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Models/Ninja.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Models +{ + public class Ninja + { + public string Key { get; set; } + public Clan Clan { get; set; } + public string Name { get; set; } + public int Level { get; set; } + } +} diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Models/NinjaEntity.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Models/NinjaEntity.cs new file mode 100644 index 0000000..12906d9 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Models/NinjaEntity.cs @@ -0,0 +1,14 @@ +using Microsoft.WindowsAzure.Storage.Table; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Models +{ + public class NinjaEntity : TableEntity + { + public string Name { get; set; } + public int Level { get; set; } + } +} diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Program.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Program.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Program.cs rename to 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Program.cs diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Properties/launchSettings.json b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Properties/launchSettings.json new file mode 100644 index 0000000..5285189 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:2439/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "v1/ninja", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "ForEvolve.Blog.Samples.NinjaApi": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "api/values", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:2440/" + } + } +} \ No newline at end of file diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/ClanRepository.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/ClanRepository.cs new file mode 100644 index 0000000..c3f5176 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/ClanRepository.cs @@ -0,0 +1,45 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System; +using System.Linq; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Repositories +{ + public class ClanRepository : IClanRepository + { + private readonly List _clans; + + public ClanRepository(IEnumerable clans) + { + if (clans == null) { throw new ArgumentNullException(nameof(clans)); } + _clans = new List(clans); + } + + public Task> ReadAllAsync() + { + return Task.FromResult(_clans.AsEnumerable()); + } + + public Task ReadOneAsync(string clanName) + { + var clan = _clans.FirstOrDefault(c => c.Name == clanName); + return Task.FromResult(clan); + } + + public Task CreateAsync(Clan clan) + { + throw new NotSupportedException(); + } + + public Task UpdateAsync(Clan clan) + { + throw new NotSupportedException(); + } + + public Task DeleteAsync(string clanName) + { + throw new NotSupportedException(); + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/IClanRepository.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/IClanRepository.cs new file mode 100644 index 0000000..e2e41ed --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/IClanRepository.cs @@ -0,0 +1,16 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Repositories +{ + public interface IClanRepository + { + Task> ReadAllAsync(); + Task ReadOneAsync(string clanName); + Task CreateAsync(Clan clan); + Task UpdateAsync(Clan clan); + Task DeleteAsync(string clanName); + } +} diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/INinjaRepository.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/INinjaRepository.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/INinjaRepository.cs rename to 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/INinjaRepository.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/NinjaRepository.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/NinjaRepository.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/NinjaRepository.cs rename to 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/NinjaRepository.cs diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/ClanService.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/ClanService.cs new file mode 100644 index 0000000..d6b6118 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/ClanService.cs @@ -0,0 +1,49 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Repositories; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public class ClanService : IClanService + { + private IClanRepository _clanRepository; + + public ClanService(IClanRepository clanRepository) + { + _clanRepository = clanRepository ?? throw new ArgumentNullException(nameof(clanRepository)); + } + + public Task> ReadAllAsync() + { + return _clanRepository.ReadAllAsync(); + } + + public Task ReadOneAsync(string clanName) + { + return _clanRepository.ReadOneAsync(clanName); + } + + public async Task IsClanExistsAsync(string clanName) + { + var clan = await _clanRepository.ReadOneAsync(clanName); + return clan != null; + } + + public Task CreateAsync(Clan clan) + { + throw new NotSupportedException(); + } + + public Task UpdateAsync(Clan clan) + { + throw new NotSupportedException(); + } + + public Task DeleteAsync(string clanName) + { + throw new NotSupportedException(); + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/IClanService.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/IClanService.cs new file mode 100644 index 0000000..54843b9 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/IClanService.cs @@ -0,0 +1,17 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public interface IClanService + { + Task> ReadAllAsync(); + Task ReadOneAsync(string clanName); + Task IsClanExistsAsync(string clanName); + Task CreateAsync(Clan clan); + Task UpdateAsync(Clan clan); + Task DeleteAsync(string clanName); + } +} diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaMappingService.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaMappingService.cs new file mode 100644 index 0000000..5186991 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaMappingService.cs @@ -0,0 +1,13 @@ +using ForEvolve.Blog.Samples.NinjaApi.Mappers; +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public interface INinjaMappingService : IMapper, IMapper, IMapper, IEnumerable> + { + } +} + diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaService.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaService.cs new file mode 100644 index 0000000..841069d --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaService.cs @@ -0,0 +1,17 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public interface INinjaService + { + Task> ReadAllAsync(); + Task> ReadAllInClanAsync(string clanName); + Task ReadOneAsync(string clanName, string ninjaKey); + Task CreateAsync(Ninja ninja); + Task UpdateAsync(Ninja ninja); + Task DeleteAsync(string clanName, string ninjaKey); + } +} diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaMappingService.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaMappingService.cs new file mode 100644 index 0000000..25aefbf --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaMappingService.cs @@ -0,0 +1,40 @@ +using ForEvolve.Blog.Samples.NinjaApi.Mappers; +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System; +using System.Collections.Generic; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public class NinjaMappingService : INinjaMappingService + { + private readonly IMapper _ninjaToNinjaEntityMapper; + private readonly IMapper _ninjaEntityToNinjaMapper; + private readonly IMapper, IEnumerable> _ninjaEntityEnumerableToNinjaMapper; + + public NinjaMappingService( + IMapper ninjaToNinjaEntityMapper, + IMapper ninjaEntityToNinjaMapper, + IMapper, IEnumerable> ninjaEntityEnumerableToNinjaMapper + ) + { + _ninjaToNinjaEntityMapper = ninjaToNinjaEntityMapper ?? throw new ArgumentNullException(nameof(ninjaToNinjaEntityMapper)); + _ninjaEntityToNinjaMapper = ninjaEntityToNinjaMapper ?? throw new ArgumentNullException(nameof(ninjaEntityToNinjaMapper)); + _ninjaEntityEnumerableToNinjaMapper = ninjaEntityEnumerableToNinjaMapper ?? throw new ArgumentNullException(nameof(ninjaEntityEnumerableToNinjaMapper)); + } + + public NinjaEntity Map(Ninja entity) + { + return _ninjaToNinjaEntityMapper.Map(entity); + } + + public Ninja Map(NinjaEntity entity) + { + return _ninjaEntityToNinjaMapper.Map(entity); + } + + public IEnumerable Map(IEnumerable entities) + { + return _ninjaEntityEnumerableToNinjaMapper.Map(entities); + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaService.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaService.cs new file mode 100644 index 0000000..2e96b1f --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaService.cs @@ -0,0 +1,78 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Repositories; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public class NinjaService : INinjaService + { + private readonly INinjaRepository _ninjaRepository; + private readonly IClanService _clanService; + + public NinjaService(INinjaRepository ninjaRepository, IClanService clanService) + { + _ninjaRepository = ninjaRepository ?? throw new ArgumentNullException(nameof(ninjaRepository)); + _clanService = clanService ?? throw new ArgumentNullException(nameof(clanService)); + } + + public async Task CreateAsync(Ninja ninja) + { + await EnforceClanExistenceAsync(ninja.Clan.Name); + var createdNinja = await _ninjaRepository.CreateAsync(ninja); + return createdNinja; + } + + public async Task DeleteAsync(string clanName, string ninjaKey) + { + await EnforceNinjaExistenceAsync(clanName, ninjaKey); + var deletedNinja = await _ninjaRepository.DeleteAsync(clanName, ninjaKey); + return deletedNinja; + } + + public Task> ReadAllAsync() + { + return _ninjaRepository.ReadAllAsync(); + } + + public async Task> ReadAllInClanAsync(string clanName) + { + await EnforceClanExistenceAsync(clanName); + return await _ninjaRepository.ReadAllInClanAsync(clanName); + } + + public async Task ReadOneAsync(string clanName, string ninjaKey) + { + var ninja = await EnforceNinjaExistenceAsync(clanName, ninjaKey); + return ninja; + } + + public async Task UpdateAsync(Ninja ninja) + { + await EnforceClanExistenceAsync(ninja.Clan.Name); + await EnforceNinjaExistenceAsync(ninja.Clan.Name, ninja.Key); + var updatedNinja = await _ninjaRepository.UpdateAsync(ninja); + return updatedNinja; + } + + private async Task EnforceClanExistenceAsync(string clanName) + { + var clanExist = await _clanService.IsClanExistsAsync(clanName); + if (!clanExist) + { + throw new ClanNotFoundException(clanName); + } + } + + private async Task EnforceNinjaExistenceAsync(string clanName, string ninjaKey) + { + var remoteNinja = await _ninjaRepository.ReadOneAsync(clanName, ninjaKey); + if (remoteNinja == null) + { + throw new NinjaNotFoundException(clanName, ninjaKey); + } + return remoteNinja; + } + } +} diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs rename to 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.Development.json b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.Development.json similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.Development.json rename to 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.Development.json diff --git a/8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.json b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.json similarity index 100% rename from 8. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.json rename to 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.json diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/BaseHttpTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/BaseHttpTest.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/BaseHttpTest.cs rename to 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/BaseHttpTest.cs diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ClansControllerTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ClansControllerTest.cs new file mode 100644 index 0000000..b1f2950 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ClansControllerTest.cs @@ -0,0 +1,51 @@ +using System; +using Xunit; +using Microsoft.AspNetCore.TestHost; +using System.Net.Http; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using System.Collections.Generic; +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System.Threading.Tasks; +using System.Linq; + +namespace ForEvolve.Blog.Samples.NinjaApi.IntegrationTests +{ + public class ClansControllerTest : BaseHttpTest + { + public class ReadAllAsync : ClansControllerTest + { + private IEnumerable Clans => new Clan[] { + new Clan { Name = "My clan" }, + new Clan { Name = "Your clan" }, + new Clan { Name = "His clan" } + }; + + protected override void ConfigureServices(IServiceCollection services) + { + services.AddSingleton(Clans); + } + + [Fact] + public async Task Should_return_the_default_clans() + { + // Arrange + var expectedNumberOfClans = Clans.Count(); + + // Act + var result = await Client.GetAsync("v1/clans"); + + // Assert + result.EnsureSuccessStatusCode(); + var clans = await result.Content.ReadAsJsonObjectAsync(); + Assert.NotNull(clans); + Assert.Equal(expectedNumberOfClans, clans.Length); + Assert.Collection(clans, + clan => Assert.Equal(Clans.ElementAt(0).Name, clans[0].Name), + clan => Assert.Equal(Clans.ElementAt(1).Name, clans[1].Name), + clan => Assert.Equal(Clans.ElementAt(2).Name, clans[2].Name) + ); + } + } + } +} diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj rename to 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaControllerTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaControllerTest.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaControllerTest.cs rename to 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaControllerTest.cs diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaEntityTableStorageRepositoryFake.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaEntityTableStorageRepositoryFake.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaEntityTableStorageRepositoryFake.cs rename to 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaEntityTableStorageRepositoryFake.cs diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs rename to 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/appsettings.json b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/appsettings.json similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/appsettings.json rename to 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/appsettings.json diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/ClansControllerTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/ClansControllerTest.cs new file mode 100644 index 0000000..bd6cec4 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/ClansControllerTest.cs @@ -0,0 +1,47 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using Microsoft.AspNetCore.Mvc; +using System; +using Xunit; +using Moq; +using ForEvolve.Blog.Samples.NinjaApi.Services; + +namespace ForEvolve.Blog.Samples.NinjaApi.Controllers +{ + public class ClansControllerTest + { + protected ClansController ControllerUnderTest { get; } + protected Mock ClanServiceMock { get; } + + public ClansControllerTest() + { + ClanServiceMock = new Mock(); + ControllerUnderTest = new ClansController(ClanServiceMock.Object); + } + + + public class ReadAllAsync : ClansControllerTest + { + [Fact] + public async void Should_return_OkObjectResult_with_clans() + { + // Arrange + var expectedClans = new Clan[] + { + new Clan { Name = "Test clan 1" }, + new Clan { Name = "Test clan 2" }, + new Clan { Name = "Test clan 3" } + }; + ClanServiceMock + .Setup(x => x.ReadAllAsync()) + .ReturnsAsync(expectedClans); + + // Act + var result = await ControllerUnderTest.ReadAllAsync(); + + // Assert + var okResult = Assert.IsType(result); + Assert.Same(expectedClans, okResult.Value); + } + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/NinjaControllerTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/NinjaControllerTest.cs new file mode 100644 index 0000000..3fec6d2 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/NinjaControllerTest.cs @@ -0,0 +1,270 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Services; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Moq; +using System; +using System.Collections.Generic; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Controllers +{ + public class NinjaControllerTest + { + protected NinjaController ControllerUnderTest { get; } + protected Mock NinjaServiceMock { get; } + + public NinjaControllerTest() + { + NinjaServiceMock = new Mock(); + ControllerUnderTest = new NinjaController(NinjaServiceMock.Object); + } + + public class ReadAllAsync : NinjaControllerTest + { + [Fact] + public async void Should_return_OkObjectResult_with_all_Ninja() + { + // Arrange + var expectedNinjas = new Ninja[] + { + new Ninja { Name = "Test Ninja 1" }, + new Ninja { Name = "Test Ninja 2" }, + new Ninja { Name = "Test Ninja 3" } + }; + NinjaServiceMock + .Setup(x => x.ReadAllAsync()) + .ReturnsAsync(expectedNinjas); + + // Act + var result = await ControllerUnderTest.ReadAllAsync(); + + // Assert + var okResult = Assert.IsType(result); + Assert.Same(expectedNinjas, okResult.Value); + } + } + + public class ReadAllInClanAsync : NinjaControllerTest + { + [Fact] + public async void Should_return_OkObjectResult_with_all_Ninja_in_Clan() + { + // Arrange + var clanName = "Some clan name"; + var expectedNinjas = new Ninja[] + { + new Ninja { Name = "Test Ninja 1" }, + new Ninja { Name = "Test Ninja 2" }, + new Ninja { Name = "Test Ninja 3" } + }; + NinjaServiceMock + .Setup(x => x.ReadAllInClanAsync(clanName)) + .ReturnsAsync(expectedNinjas); + + // Act + var result = await ControllerUnderTest.ReadAllInClanAsync(clanName); + + // Assert + var okResult = Assert.IsType(result); + Assert.Same(expectedNinjas, okResult.Value); + } + + [Fact] + public async void Should_return_NotFoundResult_when_ClanNotFoundException_is_thrown() + { + // Arrange + var unexistingClanName = "Some clan name"; + NinjaServiceMock + .Setup(x => x.ReadAllInClanAsync(unexistingClanName)) + .ThrowsAsync(new ClanNotFoundException(unexistingClanName)); + + // Act + var result = await ControllerUnderTest.ReadAllInClanAsync(unexistingClanName); + + // Assert + Assert.IsType(result); + } + } + + public class ReadOneAsync : NinjaControllerTest + { + [Fact] + public async void Should_return_OkObjectResult_with_a_Ninja() + { + // Arrange + var clanName = "Some clan name"; + var ninjaKey = "Some ninja key"; + var expectedNinja = new Ninja { Name = "Test Ninja 1" }; + NinjaServiceMock + .Setup(x => x.ReadOneAsync(clanName, ninjaKey)) + .ReturnsAsync(expectedNinja); + + // Act + var result = await ControllerUnderTest.ReadOneAsync(clanName, ninjaKey); + + // Assert + var okResult = Assert.IsType(result); + Assert.Same(expectedNinja, okResult.Value); + } + + [Fact] + public async void Should_return_NotFoundResult_when_NinjaNotFoundException_is_thrown() + { + // Arrange + var unexistingClanName = "Some clan name"; + var unexistingNinjaKey = "Some ninja key"; + NinjaServiceMock + .Setup(x => x.ReadOneAsync(unexistingClanName, unexistingNinjaKey)) + .ThrowsAsync(new NinjaNotFoundException(unexistingClanName, unexistingNinjaKey)); + + // Act + var result = await ControllerUnderTest.ReadOneAsync(unexistingClanName, unexistingNinjaKey); + + // Assert + Assert.IsType(result); + } + } + + public class CreateAsync : NinjaControllerTest + { + [Fact] + public async void Should_return_CreatedAtActionResult_with_the_created_Ninja() + { + // Arrange + var expectedNinjaKey = "SomeNinjaKey"; + var expectedClanName = "My Clan"; + var expectedCreatedAtActionName = nameof(NinjaController.ReadOneAsync); + var expectedNinja = new Ninja { Name = "Test Ninja 1", Clan = new Clan { Name = expectedClanName } }; + NinjaServiceMock + .Setup(x => x.CreateAsync(expectedNinja)) + .ReturnsAsync(() => + { + expectedNinja.Key = expectedNinjaKey; + return expectedNinja; + }); + + // Act + var result = await ControllerUnderTest.CreateAsync(expectedNinja); + + // Assert + var createdResult = Assert.IsType(result); + Assert.Same(expectedNinja, createdResult.Value); + Assert.Equal(expectedCreatedAtActionName, createdResult.ActionName); + Assert.Equal( + expectedNinjaKey, + createdResult.RouteValues.GetValueOrDefault("key") + ); + Assert.Equal( + expectedClanName, + createdResult.RouteValues.GetValueOrDefault("clan") + ); + } + + [Fact] + public async void Should_return_BadRequestResult() + { + // Arrange + var ninja = new Ninja { Name = "Test Ninja 1" }; + ControllerUnderTest.ModelState.AddModelError("Key", "Some error"); + + // Act + var result = await ControllerUnderTest.CreateAsync(ninja); + + // Assert + var badRequestResult = Assert.IsType(result); + Assert.IsType(badRequestResult.Value); + } + } + + public class UpdateAsync : NinjaControllerTest + { + [Fact] + public async void Should_return_OkObjectResult_with_the_updated_Ninja() + { + // Arrange + var expectedNinja = new Ninja { Name = "Test Ninja 1" }; + NinjaServiceMock + .Setup(x => x.UpdateAsync(expectedNinja)) + .ReturnsAsync(expectedNinja); + + // Act + var result = await ControllerUnderTest.UpdateAsync(expectedNinja); + + // Assert + var createdResult = Assert.IsType(result); + Assert.Same(expectedNinja, createdResult.Value); + } + + [Fact] + public async void Should_return_NotFoundResult_when_NinjaNotFoundException_is_thrown() + { + // Arrange + var unexistingNinja = new Ninja { Name = "Test Ninja 1", Clan = new Clan { Name = "Some clan" } }; + NinjaServiceMock + .Setup(x => x.UpdateAsync(unexistingNinja)) + .ThrowsAsync(new NinjaNotFoundException(unexistingNinja)); + + // Act + var result = await ControllerUnderTest.UpdateAsync(unexistingNinja); + + // Assert + Assert.IsType(result); + } + + [Fact] + public async void Should_return_BadRequestResult() + { + // Arrange + var ninja = new Ninja { Name = "Test Ninja 1" }; + ControllerUnderTest.ModelState.AddModelError("Key", "Some error"); + + // Act + var result = await ControllerUnderTest.UpdateAsync(ninja); + + // Assert + var badRequestResult = Assert.IsType(result); + Assert.IsType(badRequestResult.Value); + } + } + + public class DeleteAsync : NinjaControllerTest + { + [Fact] + public async void Should_return_OkObjectResult_with_the_deleted_Ninja() + { + // Arrange + var clanName = "My clan"; + var ninjaKey = "Some key"; + var expectedNinja = new Ninja { Name = "Test Ninja 1" }; + NinjaServiceMock + .Setup(x => x.DeleteAsync(clanName, ninjaKey)) + .ReturnsAsync(expectedNinja); + + // Act + var result = await ControllerUnderTest.DeleteAsync(clanName, ninjaKey); + + // Assert + var createdResult = Assert.IsType(result); + Assert.Same(expectedNinja, createdResult.Value); + } + + [Fact] + public async void Should_return_NotFoundResult_when_NinjaNotFoundException_is_thrown() + { + // Arrange + var unexistingClanName = "Some clan name"; + var unexistingNinjaKey = "Some ninja key"; + NinjaServiceMock + .Setup(x => x.DeleteAsync(unexistingClanName, unexistingNinjaKey)) + .ThrowsAsync(new NinjaNotFoundException(unexistingClanName, unexistingNinjaKey)); + + // Act + var result = await ControllerUnderTest.DeleteAsync(unexistingClanName, unexistingNinjaKey); + + // Assert + Assert.IsType(result); + } + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/ForEvolve.Blog.Samples.NinjaApi.Tests.csproj b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/ForEvolve.Blog.Samples.NinjaApi.Tests.csproj new file mode 100644 index 0000000..cf0b996 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/ForEvolve.Blog.Samples.NinjaApi.Tests.csproj @@ -0,0 +1,22 @@ + + + + netcoreapp2.0 + + false + + ForEvolve.Blog.Samples.NinjaApi + + + + + + + + + + + + + + diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs new file mode 100644 index 0000000..145e2a7 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs @@ -0,0 +1,45 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using Moq; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public class NinjaEntityEnumerableToNinjaMapperTest + { + protected NinjaEntityEnumerableToNinjaMapper MapperUnderTest { get; } + protected Mock> NinjaEntityToNinjaMapperMock { get; } + + public NinjaEntityEnumerableToNinjaMapperTest() + { + NinjaEntityToNinjaMapperMock = new Mock>(); + MapperUnderTest = new NinjaEntityEnumerableToNinjaMapper(NinjaEntityToNinjaMapperMock.Object); + } + + public class Map : NinjaEntityEnumerableToNinjaMapperTest + { + [Fact] + public void Should_delegate_mapping_to_the_sinlge_entity_mapper() + { + // Arrange + var ninja1 = new NinjaEntity(); + var ninja2 = new NinjaEntity(); + var ninjaEntities = new List { ninja1, ninja2 }; + + NinjaEntityToNinjaMapperMock + .Setup(x => x.Map(It.IsAny())) + .Returns(new Ninja()) + .Verifiable(); + + // Act + var result = MapperUnderTest.Map(ninjaEntities); + + // Assert + NinjaEntityToNinjaMapperMock.Verify(x => x.Map(ninja1), Times.Once); + NinjaEntityToNinjaMapperMock.Verify(x => x.Map(ninja2), Times.Once); + } + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityToNinjaMapperTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityToNinjaMapperTest.cs new file mode 100644 index 0000000..699f0a4 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityToNinjaMapperTest.cs @@ -0,0 +1,41 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public class NinjaEntityToNinjaMapperTest + { + protected NinjaEntityToNinjaMapper MapperUnderTest { get; } + + public NinjaEntityToNinjaMapperTest() + { + MapperUnderTest = new NinjaEntityToNinjaMapper(); + } + + public class Map : NinjaEntityToNinjaMapperTest + { + [Fact] + public void Should_return_a_well_formatted_ninja() + { + // Arrange + var entity = new NinjaEntity + { + Level = 10, + Name = "Some fake name", + PartitionKey = "Some clan name", + RowKey = "Some ninja key" + }; + + // Act + var result = MapperUnderTest.Map(entity); + + // Assert + Assert.Equal(10, result.Level); + Assert.Equal("Some fake name", result.Name); + Assert.NotNull(result.Clan); + Assert.Equal("Some clan name", result.Clan.Name); + Assert.Equal("Some ninja key", result.Key); + } + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaToNinjaEntityMapperTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaToNinjaEntityMapperTest.cs new file mode 100644 index 0000000..1a08e1c --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaToNinjaEntityMapperTest.cs @@ -0,0 +1,43 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public class NinjaToNinjaEntityMapperTest + { + protected NinjaToNinjaEntityMapper MapperUnderTest { get; } + + public NinjaToNinjaEntityMapperTest() + { + MapperUnderTest = new NinjaToNinjaEntityMapper(); + } + + public class Map : NinjaToNinjaEntityMapperTest + { + [Fact] + public void Should_return_a_well_formatted_entity() + { + // Arrange + var ninja = new Ninja + { + Key = "Some key", + Name = "Some name", + Level = 45, + Clan = new Clan { Name = "Super clan" } + }; + + // Act + var result = MapperUnderTest.Map(ninja); + + // Assert + Assert.Equal("Some key", result.RowKey); + Assert.Equal("Some name", result.Name); + Assert.Equal(45, result.Level); + Assert.Equal("Super clan", result.PartitionKey); + } + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/ClanRepositoryTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/ClanRepositoryTest.cs new file mode 100644 index 0000000..ea77e7b --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/ClanRepositoryTest.cs @@ -0,0 +1,103 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Repositories +{ + public class ClanRepositoryTest + { + protected ClanRepository RepositoryUnderTest { get; } + protected Clan[] Clans { get; } + + public ClanRepositoryTest() + { + Clans = new Clan[] + { + new Clan { Name = "My clan" }, + new Clan { Name = "Your clan" }, + new Clan { Name = "His clan" } + }; + RepositoryUnderTest = new ClanRepository(Clans); + } + + public class ReadAllAsync : ClanRepositoryTest + { + [Fact] + public async Task Should_return_all_clans() + { + // Act + var result = await RepositoryUnderTest.ReadAllAsync(); + + // Assert + Assert.Collection(result, + clan => Assert.Same(Clans[0], clan), + clan => Assert.Same(Clans[1], clan), + clan => Assert.Same(Clans[2], clan) + ); + } + } + + public class ReadOneAsync : ClanRepositoryTest + { + [Fact] + public async Task Should_return_the_expected_clan() + { + // Arrange + var expectedClan = Clans[1]; + var expectedClanName = expectedClan.Name; + + // Act + var result = await RepositoryUnderTest.ReadOneAsync(expectedClanName); + + // Assert + Assert.Same(expectedClan, result); + } + + [Fact] + public async Task Should_return_null_if_the_clan_does_not_exist() + { + // Arrange + var unexistingClanName = "Unexisting clan"; + + // Act + var result = await RepositoryUnderTest.ReadOneAsync(unexistingClanName); + + // Assert + Assert.Null(result); + } + } + + public class CreateAsync : ClanRepositoryTest + { + [Fact] + public async Task Should_throw_a_NotSupportedException() + { + // Arrange, Act, Assert + var exception = await Assert.ThrowsAsync(() => RepositoryUnderTest.CreateAsync(null)); + } + } + + public class UpdateAsync : ClanRepositoryTest + { + [Fact] + public async Task Should_throw_a_NotSupportedException() + { + // Arrange, Act, Assert + var exception = await Assert.ThrowsAsync(() => RepositoryUnderTest.UpdateAsync(null)); + } + } + + public class DeleteAsync : ClanRepositoryTest + { + [Fact] + public async Task Should_throw_a_NotSupportedException() + { + // Arrange, Act, Assert + var exception = await Assert.ThrowsAsync(() => RepositoryUnderTest.DeleteAsync(null)); + } + } + } +} diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/NinjaRepositoryTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/NinjaRepositoryTest.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/NinjaRepositoryTest.cs rename to 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/NinjaRepositoryTest.cs diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/ClanServiceTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/ClanServiceTest.cs new file mode 100644 index 0000000..bba7c70 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/ClanServiceTest.cs @@ -0,0 +1,149 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Repositories; +using Moq; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public class ClanServiceTest + { + protected ClanService ServiceUnderTest { get; } + protected Mock ClanRepositoryMock { get; } + + public ClanServiceTest() + { + ClanRepositoryMock = new Mock(); + ServiceUnderTest = new ClanService(ClanRepositoryMock.Object); + } + + public class ReadAllAsync : ClanServiceTest + { + [Fact] + public async Task Should_return_all_clans() + { + // Arrange + var expectedClans = new ReadOnlyCollection(new List + { + new Clan { Name = "My Clan" }, + new Clan { Name = "Your Clan" }, + new Clan { Name = "His Clan" } + }); + ClanRepositoryMock + .Setup(x => x.ReadAllAsync()) + .ReturnsAsync(expectedClans); + + // Act + var result = await ServiceUnderTest.ReadAllAsync(); + + // Assert + Assert.Same(expectedClans, result); + } + } + + public class ReadOneAsync : ClanServiceTest + { + [Fact] + public async Task Should_return_the_expected_clan() + { + // Arrange + var clanName = "My Clan"; + var expectedClan = new Clan { Name = clanName }; + ClanRepositoryMock + .Setup(x => x.ReadOneAsync(clanName)) + .ReturnsAsync(expectedClan); + + // Act + var result = await ServiceUnderTest.ReadOneAsync(clanName); + + // Assert + Assert.Same(expectedClan, result); + } + + [Fact] + public async Task Should_return_null_if_the_clan_does_not_exist() + { + // Arrange + var clanName = "My Clan"; + ClanRepositoryMock + .Setup(x => x.ReadOneAsync(clanName)) + .ReturnsAsync(default(Clan)); + + // Act + var result = await ServiceUnderTest.ReadOneAsync(clanName); + + // Assert + Assert.Null(result); + } + } + + public class IsClanExistsAsync : ClanServiceTest + { + [Fact] + public async Task Should_return_true_if_the_clan_exist() + { + // Arrange + var clanName = "Your Clan"; + ClanRepositoryMock + .Setup(x => x.ReadOneAsync(clanName)) + .ReturnsAsync(new Clan()); + + // Act + var result = await ServiceUnderTest.IsClanExistsAsync(clanName); + + // Assert + Assert.True(result); + } + + [Fact] + public async Task Should_return_false_if_the_clan_does_not_exist() + { + // Arrange + var clanName = "Unexisting Clan"; + ClanRepositoryMock + .Setup(x => x.ReadOneAsync(clanName)) + .ReturnsAsync(default(Clan)); + + // Act + var result = await ServiceUnderTest.IsClanExistsAsync(clanName); + + // Assert + Assert.False(result); + } + } + + public class CreateAsync : ClanServiceTest + { + [Fact] + public async Task Should_throw_a_NotSupportedException() + { + // Arrange, Act, Assert + var exception = await Assert.ThrowsAsync(() => ServiceUnderTest.CreateAsync(null)); + } + } + + public class UpdateAsync : ClanServiceTest + { + [Fact] + public async Task Should_throw_a_NotSupportedException() + { + // Arrange, Act, Assert + var exception = await Assert.ThrowsAsync(() => ServiceUnderTest.UpdateAsync(null)); + } + } + + public class DeleteAsync : ClanServiceTest + { + [Fact] + public async Task Should_throw_a_NotSupportedException() + { + // Arrange, Act, Assert + var exception = await Assert.ThrowsAsync(() => ServiceUnderTest.DeleteAsync(null)); + } + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaMappingServiceTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaMappingServiceTest.cs new file mode 100644 index 0000000..b0cb5df --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaMappingServiceTest.cs @@ -0,0 +1,81 @@ +using ForEvolve.Blog.Samples.NinjaApi.Mappers; +using ForEvolve.Blog.Samples.NinjaApi.Models; +using Moq; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public class NinjaMappingServiceTest + { + protected NinjaMappingService ServiceUnderTest { get; } + protected Mock> NinjaToNinjaEntityMapperMock { get; } + protected Mock> NinjaEntityToNinjaMapperMock { get; } + protected Mock, IEnumerable>> NinjaEntityEnumerableToNinjaMapperMock { get; } + + public NinjaMappingServiceTest() + { + NinjaToNinjaEntityMapperMock = new Mock>(); + NinjaEntityToNinjaMapperMock = new Mock>(); + NinjaEntityEnumerableToNinjaMapperMock = new Mock, IEnumerable>>(); + ServiceUnderTest = new NinjaMappingService( + NinjaToNinjaEntityMapperMock.Object, + NinjaEntityToNinjaMapperMock.Object, + NinjaEntityEnumerableToNinjaMapperMock.Object + ); + } + + [Fact] + public void Map_Ninja_to_NinjaEntity_should_delegate_to_NinjaToNinjaEntityMapper() + { + // Arrange + var ninja = new Ninja(); + var expectedEntity = new NinjaEntity(); + NinjaToNinjaEntityMapperMock + .Setup(x => x.Map(ninja)) + .Returns(expectedEntity); + + // Act + var result = ServiceUnderTest.Map(ninja); + + // Assert + Assert.Same(expectedEntity, result); + } + + [Fact] + public void Map_NinjaEntity_to_Ninja_should_delegate_to_NinjaEntityToNinjaMapper() + { + // Arrange + var ninjaEntity = new NinjaEntity(); + var expectedNinja = new Ninja(); + NinjaEntityToNinjaMapperMock + .Setup(x => x.Map(ninjaEntity)) + .Returns(expectedNinja); + + // Act + var result = ServiceUnderTest.Map(ninjaEntity); + + // Assert + Assert.Same(expectedNinja, result); + } + + [Fact] + public void Map_NinjaEntityEnumerable_to_NinjaEnumerable_should_delegate_to_NinjaEntityEnumerableToNinjaMapper() + { + // Arrange + var ninjaEntities = new List(); + var expectedNinja = new List(); + NinjaEntityEnumerableToNinjaMapperMock + .Setup(x => x.Map(ninjaEntities)) + .Returns(expectedNinja); + + // Act + var result = ServiceUnderTest.Map(ninjaEntities); + + // Assert + Assert.Same(expectedNinja, result); + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaServiceTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaServiceTest.cs new file mode 100644 index 0000000..95180fe --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaServiceTest.cs @@ -0,0 +1,323 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Repositories; +using Microsoft.AspNetCore.Mvc; +using Moq; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public class NinjaServiceTest + { + protected NinjaService ServiceUnderTest { get; } + protected Mock NinjaRepositoryMock { get; } + protected Mock ClanServiceMock { get; } + + public NinjaServiceTest() + { + NinjaRepositoryMock = new Mock(); + ClanServiceMock = new Mock(); + ServiceUnderTest = new NinjaService(NinjaRepositoryMock.Object, ClanServiceMock.Object); + } + + public class ReadAllAsync : NinjaServiceTest + { + [Fact] + public async void Should_return_all_Ninja() + { + // Arrange + var expectedNinjas = new Ninja[] + { + new Ninja { Name = "Test Ninja 1" }, + new Ninja { Name = "Test Ninja 2" }, + new Ninja { Name = "Test Ninja 3" } + }; + NinjaRepositoryMock + .Setup(x => x.ReadAllAsync()) + .ReturnsAsync(expectedNinjas); + + // Act + var result = await ServiceUnderTest.ReadAllAsync(); + + // Assert + Assert.Same(expectedNinjas, result); + } + } + + public class ReadAllInClanAsync : NinjaServiceTest + { + [Fact] + public async void Should_return_all_Ninja_in_Clan() + { + // Arrange + var clanName = "Some clan name"; + var expectedNinjas = new Ninja[] + { + new Ninja { Name = "Test Ninja 1" }, + new Ninja { Name = "Test Ninja 2" }, + new Ninja { Name = "Test Ninja 3" } + }; + NinjaRepositoryMock + .Setup(x => x.ReadAllInClanAsync(clanName)) + .ReturnsAsync(expectedNinjas) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(clanName)) + .ReturnsAsync(true) + .Verifiable(); + + // Act + var result = await ServiceUnderTest.ReadAllInClanAsync(clanName); + + // Assert + Assert.Same(expectedNinjas, result); + NinjaRepositoryMock + .Verify(x => x.ReadAllInClanAsync(clanName), Times.Once); + ClanServiceMock + .Verify(x => x.IsClanExistsAsync(clanName), Times.Once); + } + + [Fact] + public async void Should_throw_ClanNotFoundException_when_clan_does_not_exist() + { + // Arrange + var unexistingClanName = "Some clan name"; + NinjaRepositoryMock + .Setup(x => x.ReadAllInClanAsync(unexistingClanName)) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(unexistingClanName)) + .ReturnsAsync(false) + .Verifiable(); + + // Act & Assert + await Assert.ThrowsAsync(() => ServiceUnderTest.ReadAllInClanAsync(unexistingClanName)); + + NinjaRepositoryMock + .Verify(x => x.ReadAllInClanAsync(unexistingClanName), Times.Never); + ClanServiceMock + .Verify(x => x.IsClanExistsAsync(unexistingClanName), Times.Once); + } + } + + public class ReadOneAsync : NinjaServiceTest + { + [Fact] + public async void Should_return_OkObjectResult_with_a_Ninja() + { + // Arrange + var clanName = "Some clan name"; + var ninjaKey = "Some ninja key"; + var expectedNinja = new Ninja { Name = "Test Ninja 1" }; + NinjaRepositoryMock + .Setup(x => x.ReadOneAsync(clanName, ninjaKey)) + .ReturnsAsync(expectedNinja); + + // Act + var result = await ServiceUnderTest.ReadOneAsync(clanName, ninjaKey); + + // Assert + Assert.Same(expectedNinja, result); + } + + [Fact] + public async void Should_throw_NinjaNotFoundException_when_ninja_does_not_exist() + { + // Arrange + var unexistingClanName = "Some clan name"; + var unexistingNinjaKey = "Some ninja key"; + NinjaRepositoryMock + .Setup(x => x.ReadOneAsync(unexistingClanName, unexistingNinjaKey)) + .ReturnsAsync(default(Ninja)); + + // Act & Assert + await Assert.ThrowsAsync(() => ServiceUnderTest.ReadOneAsync(unexistingClanName, unexistingNinjaKey)); + } + } + + public class CreateAsync : NinjaServiceTest + { + [Fact] + public async void Should_create_and_return_the_created_Ninja() + { + // Arrange + const string clanName = "Some clan name"; + var expectedNinja = new Ninja { Clan = new Clan { Name = clanName } }; + NinjaRepositoryMock + .Setup(x => x.CreateAsync(expectedNinja)) + .ReturnsAsync(expectedNinja) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(clanName)) + .ReturnsAsync(true); + + // Act + var result = await ServiceUnderTest.CreateAsync(expectedNinja); + + // Assert + Assert.Same(expectedNinja, result); + NinjaRepositoryMock.Verify(x => x.CreateAsync(expectedNinja), Times.Once); + } + + [Fact] + public async void Should_throw_a_ClanNotFoundException_when_clan_does_not_exist() + { + const string clanName = "Some clan name"; + var expectedNinja = new Ninja { Clan = new Clan { Name = clanName } }; + NinjaRepositoryMock + .Setup(x => x.CreateAsync(expectedNinja)) + .ReturnsAsync(expectedNinja) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(clanName)) + .ReturnsAsync(false); + + // Act & Assert + await Assert.ThrowsAsync(() => ServiceUnderTest.CreateAsync(expectedNinja)); + + // Make sure CreateAsync is never called + NinjaRepositoryMock.Verify(x => x.CreateAsync(expectedNinja), Times.Never); + } + } + + public class UpdateAsync : NinjaServiceTest + { + [Fact] + public async void Should_update_and_return_the_updated_Ninja() + { + // Arrange + const string ninjaKey = "Some key"; + const string clanKey = "Some clan"; + var expectedNinja = new Ninja + { + Key = ninjaKey, + Clan = new Clan { Name = clanKey } + }; + NinjaRepositoryMock + .Setup(x => x.ReadOneAsync(clanKey, ninjaKey)) + .ReturnsAsync(expectedNinja); + NinjaRepositoryMock + .Setup(x => x.UpdateAsync(expectedNinja)) + .ReturnsAsync(expectedNinja) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(clanKey)) + .ReturnsAsync(true); + + // Act + var result = await ServiceUnderTest.UpdateAsync(expectedNinja); + + // Assert + Assert.Same(expectedNinja, result); + NinjaRepositoryMock.Verify(x => x.UpdateAsync(expectedNinja), Times.Once); + } + + [Fact] + public async void Should_throw_NinjaNotFoundException_when_ninja_does_not_exist() + { + // Arrange + const string ninjaKey = "SomeKey"; + const string clanKey = "Some clan"; + var unexistingNinja = new Ninja { Key = ninjaKey, Clan = new Clan { Name = clanKey } }; + NinjaRepositoryMock + .Setup(x => x.UpdateAsync(unexistingNinja)) + .Verifiable(); + NinjaRepositoryMock + .Setup(x => x.ReadOneAsync(clanKey, ninjaKey)) + .ReturnsAsync(default(Ninja)) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(clanKey)) + .ReturnsAsync(true); + + // Act & Assert + await Assert.ThrowsAsync(() => ServiceUnderTest.UpdateAsync(unexistingNinja)); + + // Make sure UpdateAsync is never hit + NinjaRepositoryMock + .Verify(x => x.UpdateAsync(unexistingNinja), Times.Never); + + // Make sure we read the ninja from the repository before attempting an update. + NinjaRepositoryMock + .Verify(x => x.ReadOneAsync(clanKey, ninjaKey), Times.Once); + } + + [Fact] + public async void Should_throw_a_ClanNotFoundException_when_clan_does_not_exist() + { + // Arrange + const string ninjaKey = "SomeKey"; + const string clanKey = "Some clan"; + var unexistingNinja = new Ninja { Key = ninjaKey, Clan = new Clan { Name = clanKey } }; + NinjaRepositoryMock + .Setup(x => x.UpdateAsync(unexistingNinja)) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(clanKey)) + .ReturnsAsync(false); + + // Act & Assert + await Assert.ThrowsAsync(() => ServiceUnderTest.UpdateAsync(unexistingNinja)); + + // Make sure UpdateAsync is never called + NinjaRepositoryMock + .Verify(x => x.UpdateAsync(unexistingNinja), Times.Never); + } + } + + public class DeleteAsync : NinjaServiceTest + { + [Fact] + public async void Should_delete_and_return_the_deleted_Ninja() + { + // Arrange + var clanName = "My clan"; + var ninjaKey = "Some key"; + var expectedNinja = new Ninja { Name = "Test Ninja 1" }; + NinjaRepositoryMock + .Setup(x => x.DeleteAsync(clanName, ninjaKey)) + .ReturnsAsync(expectedNinja) + .Verifiable(); + NinjaRepositoryMock + .Setup(x => x.ReadOneAsync(clanName, ninjaKey)) + .ReturnsAsync(expectedNinja); + + // Act + var result = await ServiceUnderTest.DeleteAsync(clanName, ninjaKey); + + // Assert + Assert.Same(expectedNinja, result); + NinjaRepositoryMock.Verify(x => x.DeleteAsync(clanName, ninjaKey), Times.Once); + } + + [Fact] + public async void Should_throw_NinjaNotFoundException_when_ninja_does_not_exist() + { + // Arrange + const string clanName = "Some clan name"; + const string ninjaKey = "Some ninja key"; + + NinjaRepositoryMock + .Setup(x => x.DeleteAsync(clanName, ninjaKey)) + .Verifiable(); + NinjaRepositoryMock + .Setup(x => x.ReadOneAsync(clanName, ninjaKey)) + .ReturnsAsync(default(Ninja)) + .Verifiable(); + + // Act & Assert + await Assert.ThrowsAsync(() => ServiceUnderTest.DeleteAsync(clanName, ninjaKey)); + + // Make sure UpdateAsync is never hit + NinjaRepositoryMock + .Verify(x => x.DeleteAsync(clanName, ninjaKey), Times.Never); + + // Make sure we read the ninja from the repository before attempting an update. + NinjaRepositoryMock + .Verify(x => x.ReadOneAsync(clanName, ninjaKey), Times.Once); + } + } + } +} \ No newline at end of file diff --git a/8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/TestDataFactory.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/TestDataFactory.cs similarity index 100% rename from 8. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/TestDataFactory.cs rename to 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/TestDataFactory.cs diff --git a/8. NinjaApi - NinjaEntity/ForEvolve.Blog.Samples.NinjaApi.sln b/8. NinjaApi - NinjaEntity/ForEvolve.Blog.Samples.NinjaApi.sln new file mode 100644 index 0000000..48f81a9 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/ForEvolve.Blog.Samples.NinjaApi.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26711.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{23BF447F-B872-4D4F-8F28-D443072AE93E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{2F55FE43-6EA6-4A7E-B70B-2E8267478F29}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ForEvolve.Blog.Samples.NinjaApi", "src\ForEvolve.Blog.Samples.NinjaApi\ForEvolve.Blog.Samples.NinjaApi.csproj", "{DD219D97-6BF6-4EE5-9E35-13185F4FA261}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ForEvolve.Blog.Samples.NinjaApi.Tests", "test\ForEvolve.Blog.Samples.NinjaApi.Tests\ForEvolve.Blog.Samples.NinjaApi.Tests.csproj", "{6705EB4C-3DF6-4385-AEAB-3EE2FE074E05}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ForEvolve.Blog.Samples.NinjaApi.IntegrationTests", "test\ForEvolve.Blog.Samples.NinjaApi.IntegrationTests\ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj", "{89C4A3D5-7272-4EC7-AC91-89ED8C1D00EA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DD219D97-6BF6-4EE5-9E35-13185F4FA261}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD219D97-6BF6-4EE5-9E35-13185F4FA261}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD219D97-6BF6-4EE5-9E35-13185F4FA261}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DD219D97-6BF6-4EE5-9E35-13185F4FA261}.Release|Any CPU.Build.0 = Release|Any CPU + {6705EB4C-3DF6-4385-AEAB-3EE2FE074E05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6705EB4C-3DF6-4385-AEAB-3EE2FE074E05}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6705EB4C-3DF6-4385-AEAB-3EE2FE074E05}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6705EB4C-3DF6-4385-AEAB-3EE2FE074E05}.Release|Any CPU.Build.0 = Release|Any CPU + {89C4A3D5-7272-4EC7-AC91-89ED8C1D00EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {89C4A3D5-7272-4EC7-AC91-89ED8C1D00EA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {89C4A3D5-7272-4EC7-AC91-89ED8C1D00EA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {89C4A3D5-7272-4EC7-AC91-89ED8C1D00EA}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {DD219D97-6BF6-4EE5-9E35-13185F4FA261} = {23BF447F-B872-4D4F-8F28-D443072AE93E} + {6705EB4C-3DF6-4385-AEAB-3EE2FE074E05} = {2F55FE43-6EA6-4A7E-B70B-2E8267478F29} + {89C4A3D5-7272-4EC7-AC91-89ED8C1D00EA} = {2F55FE43-6EA6-4A7E-B70B-2E8267478F29} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {47DBF882-4F3A-4C9F-95CC-1286279CC35B} + EndGlobalSection +EndGlobal diff --git a/8. NinjaApi - NinjaEntity/README.md b/8. NinjaApi - NinjaEntity/README.md new file mode 100644 index 0000000..1a80909 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/README.md @@ -0,0 +1,4 @@ +# Dependency Injection +This project contains the code sample of the +[Design Patterns: Asp.Net Core Web API, services, and repositories | Part 8: Azure table storage and the data model](http://www.forevolve.com/en/articles/2017/09/07/design-patterns-web-api-service-and-repository-part-8/) +article. \ No newline at end of file diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/ClansController.cs b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/ClansController.cs new file mode 100644 index 0000000..4e3d49d --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/ClansController.cs @@ -0,0 +1,29 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Services; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Controllers +{ + [Route("v1/[controller]")] + public class ClansController : Controller + { + private readonly IClanService _clanService; + + public ClansController(IClanService clanService) + { + _clanService = clanService ?? throw new ArgumentNullException(nameof(clanService)); + } + + [HttpGet] + [ProducesResponseType(typeof(IEnumerable), 200)] + public async Task ReadAllAsync() + { + var allClans = await _clanService.ReadAllAsync(); + return Ok(allClans); + } + } +} diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/NinjaController.cs b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/NinjaController.cs new file mode 100644 index 0000000..7f6d7eb --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/NinjaController.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using ForEvolve.Blog.Samples.NinjaApi.Models; +using Microsoft.AspNetCore.Http; +using ForEvolve.Blog.Samples.NinjaApi.Services; + +namespace ForEvolve.Blog.Samples.NinjaApi.Controllers +{ + [Route("v1/[controller]")] + public class NinjaController : Controller + { + private readonly INinjaService _ninjaService; + public NinjaController(INinjaService ninjaService) + { + _ninjaService = ninjaService ?? throw new ArgumentNullException(nameof(ninjaService)); + } + + [HttpGet] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + public async Task ReadAllAsync() + { + var allNinja = await _ninjaService.ReadAllAsync(); + return Ok(allNinja); + } + + [HttpGet("{clan}")] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task ReadAllInClanAsync(string clan) + { + try + { + var clanNinja = await _ninjaService.ReadAllInClanAsync(clan); + return Ok(clanNinja); + } + catch (ClanNotFoundException) + { + return NotFound(); + } + } + + [HttpGet("{clan}/{key}")] + [ProducesResponseType(typeof(Ninja), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task ReadOneAsync(string clan, string key) + { + try + { + var ninja = await _ninjaService.ReadOneAsync(clan, key); + return Ok(ninja); + } + catch (NinjaNotFoundException) + { + return NotFound(); + } + } + + [HttpPost] + [ProducesResponseType(typeof(Ninja), StatusCodes.Status201Created)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task CreateAsync([FromBody]Ninja ninja) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + var createdNinja = await _ninjaService.CreateAsync(ninja); + return CreatedAtAction( + nameof(ReadOneAsync), + new { clan = createdNinja.Clan.Name, key = createdNinja.Key }, + createdNinja + ); + } + + [HttpPut] + [ProducesResponseType(typeof(Ninja), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task UpdateAsync([FromBody]Ninja ninja) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + try + { + var updatedNinja = await _ninjaService.UpdateAsync(ninja); + return Ok(updatedNinja); + } + catch (NinjaNotFoundException) + { + return NotFound(); + } + } + + [HttpDelete("{clan}/{key}")] + [ProducesResponseType(typeof(Ninja), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task DeleteAsync(string clan, string key) + { + try + { + var deletedNinja = await _ninjaService.DeleteAsync(clan, key); + return Ok(deletedNinja); + } + catch (NinjaNotFoundException) + { + return NotFound(); + } + } + } +} diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/ClanNotFoundException.cs b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/ClanNotFoundException.cs new file mode 100644 index 0000000..7d55c95 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/ClanNotFoundException.cs @@ -0,0 +1,17 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; + +namespace ForEvolve.Blog.Samples.NinjaApi +{ + public class ClanNotFoundException : NinjaApiException + { + public ClanNotFoundException(Clan clan) + : this(clan.Name) + { + } + + public ClanNotFoundException(string clanName) + : base($"Clan {clanName} was not found.") + { + } + } +} diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaApiException.cs b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaApiException.cs new file mode 100644 index 0000000..ff81d64 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaApiException.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi +{ + public class NinjaApiException : Exception + { + public NinjaApiException() + { + } + + public NinjaApiException(string message) : base(message) + { + } + + public NinjaApiException(string message, Exception innerException) : base(message, innerException) + { + } + + protected NinjaApiException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaNotFoundException.cs b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaNotFoundException.cs new file mode 100644 index 0000000..54c1d8d --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaNotFoundException.cs @@ -0,0 +1,17 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; + +namespace ForEvolve.Blog.Samples.NinjaApi +{ + public class NinjaNotFoundException : NinjaApiException + { + public NinjaNotFoundException(Ninja ninja) + : base($"Ninja {ninja.Name} ({ninja.Key}) of clan {ninja.Clan.Name} was not found.") + { + } + + public NinjaNotFoundException(string clanName, string ninjaKey) + : base($"Ninja {ninjaKey} of clan {clanName} was not found.") + { + } + } +} diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj new file mode 100644 index 0000000..4c0cd14 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj @@ -0,0 +1,18 @@ + + + + netcoreapp2.0 + aspnet-ForEvolve.Blog.Samples.NinjaApi-F62B525A-ACF4-4C7C-BF23-1EB0F434DDE5 + Full + + + + + + + + + + + + diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Models/Clan.cs b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Models/Clan.cs new file mode 100644 index 0000000..7b7c615 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Models/Clan.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Models +{ + public class Clan + { + public string Name { get; set; } + } +} diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Models/Ninja.cs b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Models/Ninja.cs new file mode 100644 index 0000000..110e285 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Models/Ninja.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Models +{ + public class Ninja + { + public string Key { get; set; } + public Clan Clan { get; set; } + public string Name { get; set; } + public int Level { get; set; } + } +} diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Models/NinjaEntity.cs b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Models/NinjaEntity.cs new file mode 100644 index 0000000..12906d9 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Models/NinjaEntity.cs @@ -0,0 +1,14 @@ +using Microsoft.WindowsAzure.Storage.Table; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Models +{ + public class NinjaEntity : TableEntity + { + public string Name { get; set; } + public int Level { get; set; } + } +} diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Program.cs b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Program.cs new file mode 100644 index 0000000..88c9273 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Program.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace ForEvolve.Blog.Samples.NinjaApi +{ + public class Program + { + public static void Main(string[] args) + { + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup() + .Build(); + } +} diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Properties/launchSettings.json b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Properties/launchSettings.json new file mode 100644 index 0000000..5285189 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:2439/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "v1/ninja", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "ForEvolve.Blog.Samples.NinjaApi": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "api/values", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:2440/" + } + } +} \ No newline at end of file diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/ClanRepository.cs b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/ClanRepository.cs new file mode 100644 index 0000000..c3f5176 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/ClanRepository.cs @@ -0,0 +1,45 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System; +using System.Linq; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Repositories +{ + public class ClanRepository : IClanRepository + { + private readonly List _clans; + + public ClanRepository(IEnumerable clans) + { + if (clans == null) { throw new ArgumentNullException(nameof(clans)); } + _clans = new List(clans); + } + + public Task> ReadAllAsync() + { + return Task.FromResult(_clans.AsEnumerable()); + } + + public Task ReadOneAsync(string clanName) + { + var clan = _clans.FirstOrDefault(c => c.Name == clanName); + return Task.FromResult(clan); + } + + public Task CreateAsync(Clan clan) + { + throw new NotSupportedException(); + } + + public Task UpdateAsync(Clan clan) + { + throw new NotSupportedException(); + } + + public Task DeleteAsync(string clanName) + { + throw new NotSupportedException(); + } + } +} diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/IClanRepository.cs b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/IClanRepository.cs new file mode 100644 index 0000000..e2e41ed --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/IClanRepository.cs @@ -0,0 +1,16 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Repositories +{ + public interface IClanRepository + { + Task> ReadAllAsync(); + Task ReadOneAsync(string clanName); + Task CreateAsync(Clan clan); + Task UpdateAsync(Clan clan); + Task DeleteAsync(string clanName); + } +} diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/INinjaRepository.cs b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/INinjaRepository.cs new file mode 100644 index 0000000..0075b92 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/INinjaRepository.cs @@ -0,0 +1,18 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Repositories +{ + public interface INinjaRepository + { + Task> ReadAllAsync(); + Task> ReadAllInClanAsync(string clanName); + Task ReadOneAsync(string clanName, string ninjaKey); + Task CreateAsync(Ninja ninja); + Task UpdateAsync(Ninja ninja); + Task DeleteAsync(string clanName, string ninjaKey); + } +} diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Services/ClanService.cs b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Services/ClanService.cs new file mode 100644 index 0000000..d6b6118 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Services/ClanService.cs @@ -0,0 +1,49 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Repositories; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public class ClanService : IClanService + { + private IClanRepository _clanRepository; + + public ClanService(IClanRepository clanRepository) + { + _clanRepository = clanRepository ?? throw new ArgumentNullException(nameof(clanRepository)); + } + + public Task> ReadAllAsync() + { + return _clanRepository.ReadAllAsync(); + } + + public Task ReadOneAsync(string clanName) + { + return _clanRepository.ReadOneAsync(clanName); + } + + public async Task IsClanExistsAsync(string clanName) + { + var clan = await _clanRepository.ReadOneAsync(clanName); + return clan != null; + } + + public Task CreateAsync(Clan clan) + { + throw new NotSupportedException(); + } + + public Task UpdateAsync(Clan clan) + { + throw new NotSupportedException(); + } + + public Task DeleteAsync(string clanName) + { + throw new NotSupportedException(); + } + } +} diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Services/IClanService.cs b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Services/IClanService.cs new file mode 100644 index 0000000..54843b9 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Services/IClanService.cs @@ -0,0 +1,17 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public interface IClanService + { + Task> ReadAllAsync(); + Task ReadOneAsync(string clanName); + Task IsClanExistsAsync(string clanName); + Task CreateAsync(Clan clan); + Task UpdateAsync(Clan clan); + Task DeleteAsync(string clanName); + } +} diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaService.cs b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaService.cs new file mode 100644 index 0000000..841069d --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaService.cs @@ -0,0 +1,17 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public interface INinjaService + { + Task> ReadAllAsync(); + Task> ReadAllInClanAsync(string clanName); + Task ReadOneAsync(string clanName, string ninjaKey); + Task CreateAsync(Ninja ninja); + Task UpdateAsync(Ninja ninja); + Task DeleteAsync(string clanName, string ninjaKey); + } +} diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaService.cs b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaService.cs new file mode 100644 index 0000000..2e96b1f --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaService.cs @@ -0,0 +1,78 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Repositories; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public class NinjaService : INinjaService + { + private readonly INinjaRepository _ninjaRepository; + private readonly IClanService _clanService; + + public NinjaService(INinjaRepository ninjaRepository, IClanService clanService) + { + _ninjaRepository = ninjaRepository ?? throw new ArgumentNullException(nameof(ninjaRepository)); + _clanService = clanService ?? throw new ArgumentNullException(nameof(clanService)); + } + + public async Task CreateAsync(Ninja ninja) + { + await EnforceClanExistenceAsync(ninja.Clan.Name); + var createdNinja = await _ninjaRepository.CreateAsync(ninja); + return createdNinja; + } + + public async Task DeleteAsync(string clanName, string ninjaKey) + { + await EnforceNinjaExistenceAsync(clanName, ninjaKey); + var deletedNinja = await _ninjaRepository.DeleteAsync(clanName, ninjaKey); + return deletedNinja; + } + + public Task> ReadAllAsync() + { + return _ninjaRepository.ReadAllAsync(); + } + + public async Task> ReadAllInClanAsync(string clanName) + { + await EnforceClanExistenceAsync(clanName); + return await _ninjaRepository.ReadAllInClanAsync(clanName); + } + + public async Task ReadOneAsync(string clanName, string ninjaKey) + { + var ninja = await EnforceNinjaExistenceAsync(clanName, ninjaKey); + return ninja; + } + + public async Task UpdateAsync(Ninja ninja) + { + await EnforceClanExistenceAsync(ninja.Clan.Name); + await EnforceNinjaExistenceAsync(ninja.Clan.Name, ninja.Key); + var updatedNinja = await _ninjaRepository.UpdateAsync(ninja); + return updatedNinja; + } + + private async Task EnforceClanExistenceAsync(string clanName) + { + var clanExist = await _clanService.IsClanExistsAsync(clanName); + if (!clanExist) + { + throw new ClanNotFoundException(clanName); + } + } + + private async Task EnforceNinjaExistenceAsync(string clanName, string ninjaKey) + { + var remoteNinja = await _ninjaRepository.ReadOneAsync(clanName, ninjaKey); + if (remoteNinja == null) + { + throw new NinjaNotFoundException(clanName, ninjaKey); + } + return remoteNinja; + } + } +} diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs new file mode 100644 index 0000000..dcfa445 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.DependencyInjection.Extensions; +using ForEvolve.Blog.Samples.NinjaApi.Services; +using ForEvolve.Blog.Samples.NinjaApi.Repositories; +using ForEvolve.Blog.Samples.NinjaApi.Models; + +namespace ForEvolve.Blog.Samples.NinjaApi +{ + public class Startup + { + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton>(new Clan[]{ + new Clan { Name = "Iga" }, + new Clan { Name = "Kōga" }, + }); + services.AddMvc(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + app.ApplicationServices.GetService(); + app.UseMvc(); + } + } +} diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.Development.json b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.Development.json new file mode 100644 index 0000000..fa8ce71 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.Development.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.json b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.json new file mode 100644 index 0000000..26bb0ac --- /dev/null +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.json @@ -0,0 +1,15 @@ +{ + "Logging": { + "IncludeScopes": false, + "Debug": { + "LogLevel": { + "Default": "Warning" + } + }, + "Console": { + "LogLevel": { + "Default": "Warning" + } + } + } +} diff --git a/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/BaseHttpTest.cs b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/BaseHttpTest.cs new file mode 100644 index 0000000..e314434 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/BaseHttpTest.cs @@ -0,0 +1,59 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Text; + +namespace ForEvolve.Blog.Samples.NinjaApi.IntegrationTests +{ + public abstract class BaseHttpTest : IDisposable + { + protected TestServer Server { get; } + protected HttpClient Client { get; } + + protected virtual Uri BaseAddress => new Uri("http://localhost"); + protected virtual string Environment => "Development"; + + public BaseHttpTest() + { + var builder = new WebHostBuilder() + .UseEnvironment(Environment) + .ConfigureServices(ConfigureServices) + .UseStartup(); + + Server = new TestServer(builder); + Client = Server.CreateClient(); + Client.BaseAddress = BaseAddress; + } + + protected virtual void ConfigureServices(IServiceCollection services) + { + } + + #region IDisposable Support + + private bool disposedValue = false; + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + Client.Dispose(); + Server.Dispose(); + } + disposedValue = true; + } + } + + public void Dispose() + { + Dispose(true); + } + + #endregion + } +} diff --git a/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ClansControllerTest.cs b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ClansControllerTest.cs new file mode 100644 index 0000000..b1f2950 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ClansControllerTest.cs @@ -0,0 +1,51 @@ +using System; +using Xunit; +using Microsoft.AspNetCore.TestHost; +using System.Net.Http; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using System.Collections.Generic; +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System.Threading.Tasks; +using System.Linq; + +namespace ForEvolve.Blog.Samples.NinjaApi.IntegrationTests +{ + public class ClansControllerTest : BaseHttpTest + { + public class ReadAllAsync : ClansControllerTest + { + private IEnumerable Clans => new Clan[] { + new Clan { Name = "My clan" }, + new Clan { Name = "Your clan" }, + new Clan { Name = "His clan" } + }; + + protected override void ConfigureServices(IServiceCollection services) + { + services.AddSingleton(Clans); + } + + [Fact] + public async Task Should_return_the_default_clans() + { + // Arrange + var expectedNumberOfClans = Clans.Count(); + + // Act + var result = await Client.GetAsync("v1/clans"); + + // Assert + result.EnsureSuccessStatusCode(); + var clans = await result.Content.ReadAsJsonObjectAsync(); + Assert.NotNull(clans); + Assert.Equal(expectedNumberOfClans, clans.Length); + Assert.Collection(clans, + clan => Assert.Equal(Clans.ElementAt(0).Name, clans[0].Name), + clan => Assert.Equal(Clans.ElementAt(1).Name, clans[1].Name), + clan => Assert.Equal(Clans.ElementAt(2).Name, clans[2].Name) + ); + } + } + } +} diff --git a/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj new file mode 100644 index 0000000..8ad286b --- /dev/null +++ b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp2.0 + + false + + + + + + + + + + + + + + diff --git a/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs new file mode 100644 index 0000000..637653f --- /dev/null +++ b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs @@ -0,0 +1,34 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; +using Microsoft.Extensions.DependencyInjection; +using System.Linq; + +namespace ForEvolve.Blog.Samples.NinjaApi.IntegrationTests +{ + public class StartupTest : BaseHttpTest + { + public class ServiceProvider : StartupTest + { + [Fact] + public void Should_return_both_Iga_and_Kōga_clans() + { + // Arrange + var serviceProvider = Server.Host.Services; + + // Act + var clans = serviceProvider.GetService>(); + + // Assert + Assert.NotNull(clans); + Assert.Equal(2, clans.Count()); + Assert.Collection(clans, + clan => Assert.Equal("Iga", clan.Name), + clan => Assert.Equal("Kōga", clan.Name) + ); + } + } + } +} diff --git a/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/ClansControllerTest.cs b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/ClansControllerTest.cs new file mode 100644 index 0000000..bd6cec4 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/ClansControllerTest.cs @@ -0,0 +1,47 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using Microsoft.AspNetCore.Mvc; +using System; +using Xunit; +using Moq; +using ForEvolve.Blog.Samples.NinjaApi.Services; + +namespace ForEvolve.Blog.Samples.NinjaApi.Controllers +{ + public class ClansControllerTest + { + protected ClansController ControllerUnderTest { get; } + protected Mock ClanServiceMock { get; } + + public ClansControllerTest() + { + ClanServiceMock = new Mock(); + ControllerUnderTest = new ClansController(ClanServiceMock.Object); + } + + + public class ReadAllAsync : ClansControllerTest + { + [Fact] + public async void Should_return_OkObjectResult_with_clans() + { + // Arrange + var expectedClans = new Clan[] + { + new Clan { Name = "Test clan 1" }, + new Clan { Name = "Test clan 2" }, + new Clan { Name = "Test clan 3" } + }; + ClanServiceMock + .Setup(x => x.ReadAllAsync()) + .ReturnsAsync(expectedClans); + + // Act + var result = await ControllerUnderTest.ReadAllAsync(); + + // Assert + var okResult = Assert.IsType(result); + Assert.Same(expectedClans, okResult.Value); + } + } + } +} diff --git a/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/NinjaControllerTest.cs b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/NinjaControllerTest.cs new file mode 100644 index 0000000..3fec6d2 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/NinjaControllerTest.cs @@ -0,0 +1,270 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Services; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Moq; +using System; +using System.Collections.Generic; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Controllers +{ + public class NinjaControllerTest + { + protected NinjaController ControllerUnderTest { get; } + protected Mock NinjaServiceMock { get; } + + public NinjaControllerTest() + { + NinjaServiceMock = new Mock(); + ControllerUnderTest = new NinjaController(NinjaServiceMock.Object); + } + + public class ReadAllAsync : NinjaControllerTest + { + [Fact] + public async void Should_return_OkObjectResult_with_all_Ninja() + { + // Arrange + var expectedNinjas = new Ninja[] + { + new Ninja { Name = "Test Ninja 1" }, + new Ninja { Name = "Test Ninja 2" }, + new Ninja { Name = "Test Ninja 3" } + }; + NinjaServiceMock + .Setup(x => x.ReadAllAsync()) + .ReturnsAsync(expectedNinjas); + + // Act + var result = await ControllerUnderTest.ReadAllAsync(); + + // Assert + var okResult = Assert.IsType(result); + Assert.Same(expectedNinjas, okResult.Value); + } + } + + public class ReadAllInClanAsync : NinjaControllerTest + { + [Fact] + public async void Should_return_OkObjectResult_with_all_Ninja_in_Clan() + { + // Arrange + var clanName = "Some clan name"; + var expectedNinjas = new Ninja[] + { + new Ninja { Name = "Test Ninja 1" }, + new Ninja { Name = "Test Ninja 2" }, + new Ninja { Name = "Test Ninja 3" } + }; + NinjaServiceMock + .Setup(x => x.ReadAllInClanAsync(clanName)) + .ReturnsAsync(expectedNinjas); + + // Act + var result = await ControllerUnderTest.ReadAllInClanAsync(clanName); + + // Assert + var okResult = Assert.IsType(result); + Assert.Same(expectedNinjas, okResult.Value); + } + + [Fact] + public async void Should_return_NotFoundResult_when_ClanNotFoundException_is_thrown() + { + // Arrange + var unexistingClanName = "Some clan name"; + NinjaServiceMock + .Setup(x => x.ReadAllInClanAsync(unexistingClanName)) + .ThrowsAsync(new ClanNotFoundException(unexistingClanName)); + + // Act + var result = await ControllerUnderTest.ReadAllInClanAsync(unexistingClanName); + + // Assert + Assert.IsType(result); + } + } + + public class ReadOneAsync : NinjaControllerTest + { + [Fact] + public async void Should_return_OkObjectResult_with_a_Ninja() + { + // Arrange + var clanName = "Some clan name"; + var ninjaKey = "Some ninja key"; + var expectedNinja = new Ninja { Name = "Test Ninja 1" }; + NinjaServiceMock + .Setup(x => x.ReadOneAsync(clanName, ninjaKey)) + .ReturnsAsync(expectedNinja); + + // Act + var result = await ControllerUnderTest.ReadOneAsync(clanName, ninjaKey); + + // Assert + var okResult = Assert.IsType(result); + Assert.Same(expectedNinja, okResult.Value); + } + + [Fact] + public async void Should_return_NotFoundResult_when_NinjaNotFoundException_is_thrown() + { + // Arrange + var unexistingClanName = "Some clan name"; + var unexistingNinjaKey = "Some ninja key"; + NinjaServiceMock + .Setup(x => x.ReadOneAsync(unexistingClanName, unexistingNinjaKey)) + .ThrowsAsync(new NinjaNotFoundException(unexistingClanName, unexistingNinjaKey)); + + // Act + var result = await ControllerUnderTest.ReadOneAsync(unexistingClanName, unexistingNinjaKey); + + // Assert + Assert.IsType(result); + } + } + + public class CreateAsync : NinjaControllerTest + { + [Fact] + public async void Should_return_CreatedAtActionResult_with_the_created_Ninja() + { + // Arrange + var expectedNinjaKey = "SomeNinjaKey"; + var expectedClanName = "My Clan"; + var expectedCreatedAtActionName = nameof(NinjaController.ReadOneAsync); + var expectedNinja = new Ninja { Name = "Test Ninja 1", Clan = new Clan { Name = expectedClanName } }; + NinjaServiceMock + .Setup(x => x.CreateAsync(expectedNinja)) + .ReturnsAsync(() => + { + expectedNinja.Key = expectedNinjaKey; + return expectedNinja; + }); + + // Act + var result = await ControllerUnderTest.CreateAsync(expectedNinja); + + // Assert + var createdResult = Assert.IsType(result); + Assert.Same(expectedNinja, createdResult.Value); + Assert.Equal(expectedCreatedAtActionName, createdResult.ActionName); + Assert.Equal( + expectedNinjaKey, + createdResult.RouteValues.GetValueOrDefault("key") + ); + Assert.Equal( + expectedClanName, + createdResult.RouteValues.GetValueOrDefault("clan") + ); + } + + [Fact] + public async void Should_return_BadRequestResult() + { + // Arrange + var ninja = new Ninja { Name = "Test Ninja 1" }; + ControllerUnderTest.ModelState.AddModelError("Key", "Some error"); + + // Act + var result = await ControllerUnderTest.CreateAsync(ninja); + + // Assert + var badRequestResult = Assert.IsType(result); + Assert.IsType(badRequestResult.Value); + } + } + + public class UpdateAsync : NinjaControllerTest + { + [Fact] + public async void Should_return_OkObjectResult_with_the_updated_Ninja() + { + // Arrange + var expectedNinja = new Ninja { Name = "Test Ninja 1" }; + NinjaServiceMock + .Setup(x => x.UpdateAsync(expectedNinja)) + .ReturnsAsync(expectedNinja); + + // Act + var result = await ControllerUnderTest.UpdateAsync(expectedNinja); + + // Assert + var createdResult = Assert.IsType(result); + Assert.Same(expectedNinja, createdResult.Value); + } + + [Fact] + public async void Should_return_NotFoundResult_when_NinjaNotFoundException_is_thrown() + { + // Arrange + var unexistingNinja = new Ninja { Name = "Test Ninja 1", Clan = new Clan { Name = "Some clan" } }; + NinjaServiceMock + .Setup(x => x.UpdateAsync(unexistingNinja)) + .ThrowsAsync(new NinjaNotFoundException(unexistingNinja)); + + // Act + var result = await ControllerUnderTest.UpdateAsync(unexistingNinja); + + // Assert + Assert.IsType(result); + } + + [Fact] + public async void Should_return_BadRequestResult() + { + // Arrange + var ninja = new Ninja { Name = "Test Ninja 1" }; + ControllerUnderTest.ModelState.AddModelError("Key", "Some error"); + + // Act + var result = await ControllerUnderTest.UpdateAsync(ninja); + + // Assert + var badRequestResult = Assert.IsType(result); + Assert.IsType(badRequestResult.Value); + } + } + + public class DeleteAsync : NinjaControllerTest + { + [Fact] + public async void Should_return_OkObjectResult_with_the_deleted_Ninja() + { + // Arrange + var clanName = "My clan"; + var ninjaKey = "Some key"; + var expectedNinja = new Ninja { Name = "Test Ninja 1" }; + NinjaServiceMock + .Setup(x => x.DeleteAsync(clanName, ninjaKey)) + .ReturnsAsync(expectedNinja); + + // Act + var result = await ControllerUnderTest.DeleteAsync(clanName, ninjaKey); + + // Assert + var createdResult = Assert.IsType(result); + Assert.Same(expectedNinja, createdResult.Value); + } + + [Fact] + public async void Should_return_NotFoundResult_when_NinjaNotFoundException_is_thrown() + { + // Arrange + var unexistingClanName = "Some clan name"; + var unexistingNinjaKey = "Some ninja key"; + NinjaServiceMock + .Setup(x => x.DeleteAsync(unexistingClanName, unexistingNinjaKey)) + .ThrowsAsync(new NinjaNotFoundException(unexistingClanName, unexistingNinjaKey)); + + // Act + var result = await ControllerUnderTest.DeleteAsync(unexistingClanName, unexistingNinjaKey); + + // Assert + Assert.IsType(result); + } + } + } +} diff --git a/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/ForEvolve.Blog.Samples.NinjaApi.Tests.csproj b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/ForEvolve.Blog.Samples.NinjaApi.Tests.csproj new file mode 100644 index 0000000..cf0b996 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/ForEvolve.Blog.Samples.NinjaApi.Tests.csproj @@ -0,0 +1,22 @@ + + + + netcoreapp2.0 + + false + + ForEvolve.Blog.Samples.NinjaApi + + + + + + + + + + + + + + diff --git a/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/ClanRepositoryTest.cs b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/ClanRepositoryTest.cs new file mode 100644 index 0000000..ea77e7b --- /dev/null +++ b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/ClanRepositoryTest.cs @@ -0,0 +1,103 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Repositories +{ + public class ClanRepositoryTest + { + protected ClanRepository RepositoryUnderTest { get; } + protected Clan[] Clans { get; } + + public ClanRepositoryTest() + { + Clans = new Clan[] + { + new Clan { Name = "My clan" }, + new Clan { Name = "Your clan" }, + new Clan { Name = "His clan" } + }; + RepositoryUnderTest = new ClanRepository(Clans); + } + + public class ReadAllAsync : ClanRepositoryTest + { + [Fact] + public async Task Should_return_all_clans() + { + // Act + var result = await RepositoryUnderTest.ReadAllAsync(); + + // Assert + Assert.Collection(result, + clan => Assert.Same(Clans[0], clan), + clan => Assert.Same(Clans[1], clan), + clan => Assert.Same(Clans[2], clan) + ); + } + } + + public class ReadOneAsync : ClanRepositoryTest + { + [Fact] + public async Task Should_return_the_expected_clan() + { + // Arrange + var expectedClan = Clans[1]; + var expectedClanName = expectedClan.Name; + + // Act + var result = await RepositoryUnderTest.ReadOneAsync(expectedClanName); + + // Assert + Assert.Same(expectedClan, result); + } + + [Fact] + public async Task Should_return_null_if_the_clan_does_not_exist() + { + // Arrange + var unexistingClanName = "Unexisting clan"; + + // Act + var result = await RepositoryUnderTest.ReadOneAsync(unexistingClanName); + + // Assert + Assert.Null(result); + } + } + + public class CreateAsync : ClanRepositoryTest + { + [Fact] + public async Task Should_throw_a_NotSupportedException() + { + // Arrange, Act, Assert + var exception = await Assert.ThrowsAsync(() => RepositoryUnderTest.CreateAsync(null)); + } + } + + public class UpdateAsync : ClanRepositoryTest + { + [Fact] + public async Task Should_throw_a_NotSupportedException() + { + // Arrange, Act, Assert + var exception = await Assert.ThrowsAsync(() => RepositoryUnderTest.UpdateAsync(null)); + } + } + + public class DeleteAsync : ClanRepositoryTest + { + [Fact] + public async Task Should_throw_a_NotSupportedException() + { + // Arrange, Act, Assert + var exception = await Assert.ThrowsAsync(() => RepositoryUnderTest.DeleteAsync(null)); + } + } + } +} diff --git a/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/ClanServiceTest.cs b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/ClanServiceTest.cs new file mode 100644 index 0000000..bba7c70 --- /dev/null +++ b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/ClanServiceTest.cs @@ -0,0 +1,149 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Repositories; +using Moq; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public class ClanServiceTest + { + protected ClanService ServiceUnderTest { get; } + protected Mock ClanRepositoryMock { get; } + + public ClanServiceTest() + { + ClanRepositoryMock = new Mock(); + ServiceUnderTest = new ClanService(ClanRepositoryMock.Object); + } + + public class ReadAllAsync : ClanServiceTest + { + [Fact] + public async Task Should_return_all_clans() + { + // Arrange + var expectedClans = new ReadOnlyCollection(new List + { + new Clan { Name = "My Clan" }, + new Clan { Name = "Your Clan" }, + new Clan { Name = "His Clan" } + }); + ClanRepositoryMock + .Setup(x => x.ReadAllAsync()) + .ReturnsAsync(expectedClans); + + // Act + var result = await ServiceUnderTest.ReadAllAsync(); + + // Assert + Assert.Same(expectedClans, result); + } + } + + public class ReadOneAsync : ClanServiceTest + { + [Fact] + public async Task Should_return_the_expected_clan() + { + // Arrange + var clanName = "My Clan"; + var expectedClan = new Clan { Name = clanName }; + ClanRepositoryMock + .Setup(x => x.ReadOneAsync(clanName)) + .ReturnsAsync(expectedClan); + + // Act + var result = await ServiceUnderTest.ReadOneAsync(clanName); + + // Assert + Assert.Same(expectedClan, result); + } + + [Fact] + public async Task Should_return_null_if_the_clan_does_not_exist() + { + // Arrange + var clanName = "My Clan"; + ClanRepositoryMock + .Setup(x => x.ReadOneAsync(clanName)) + .ReturnsAsync(default(Clan)); + + // Act + var result = await ServiceUnderTest.ReadOneAsync(clanName); + + // Assert + Assert.Null(result); + } + } + + public class IsClanExistsAsync : ClanServiceTest + { + [Fact] + public async Task Should_return_true_if_the_clan_exist() + { + // Arrange + var clanName = "Your Clan"; + ClanRepositoryMock + .Setup(x => x.ReadOneAsync(clanName)) + .ReturnsAsync(new Clan()); + + // Act + var result = await ServiceUnderTest.IsClanExistsAsync(clanName); + + // Assert + Assert.True(result); + } + + [Fact] + public async Task Should_return_false_if_the_clan_does_not_exist() + { + // Arrange + var clanName = "Unexisting Clan"; + ClanRepositoryMock + .Setup(x => x.ReadOneAsync(clanName)) + .ReturnsAsync(default(Clan)); + + // Act + var result = await ServiceUnderTest.IsClanExistsAsync(clanName); + + // Assert + Assert.False(result); + } + } + + public class CreateAsync : ClanServiceTest + { + [Fact] + public async Task Should_throw_a_NotSupportedException() + { + // Arrange, Act, Assert + var exception = await Assert.ThrowsAsync(() => ServiceUnderTest.CreateAsync(null)); + } + } + + public class UpdateAsync : ClanServiceTest + { + [Fact] + public async Task Should_throw_a_NotSupportedException() + { + // Arrange, Act, Assert + var exception = await Assert.ThrowsAsync(() => ServiceUnderTest.UpdateAsync(null)); + } + } + + public class DeleteAsync : ClanServiceTest + { + [Fact] + public async Task Should_throw_a_NotSupportedException() + { + // Arrange, Act, Assert + var exception = await Assert.ThrowsAsync(() => ServiceUnderTest.DeleteAsync(null)); + } + } + } +} diff --git a/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaServiceTest.cs b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaServiceTest.cs new file mode 100644 index 0000000..95180fe --- /dev/null +++ b/8. NinjaApi - NinjaEntity/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaServiceTest.cs @@ -0,0 +1,323 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Repositories; +using Microsoft.AspNetCore.Mvc; +using Moq; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public class NinjaServiceTest + { + protected NinjaService ServiceUnderTest { get; } + protected Mock NinjaRepositoryMock { get; } + protected Mock ClanServiceMock { get; } + + public NinjaServiceTest() + { + NinjaRepositoryMock = new Mock(); + ClanServiceMock = new Mock(); + ServiceUnderTest = new NinjaService(NinjaRepositoryMock.Object, ClanServiceMock.Object); + } + + public class ReadAllAsync : NinjaServiceTest + { + [Fact] + public async void Should_return_all_Ninja() + { + // Arrange + var expectedNinjas = new Ninja[] + { + new Ninja { Name = "Test Ninja 1" }, + new Ninja { Name = "Test Ninja 2" }, + new Ninja { Name = "Test Ninja 3" } + }; + NinjaRepositoryMock + .Setup(x => x.ReadAllAsync()) + .ReturnsAsync(expectedNinjas); + + // Act + var result = await ServiceUnderTest.ReadAllAsync(); + + // Assert + Assert.Same(expectedNinjas, result); + } + } + + public class ReadAllInClanAsync : NinjaServiceTest + { + [Fact] + public async void Should_return_all_Ninja_in_Clan() + { + // Arrange + var clanName = "Some clan name"; + var expectedNinjas = new Ninja[] + { + new Ninja { Name = "Test Ninja 1" }, + new Ninja { Name = "Test Ninja 2" }, + new Ninja { Name = "Test Ninja 3" } + }; + NinjaRepositoryMock + .Setup(x => x.ReadAllInClanAsync(clanName)) + .ReturnsAsync(expectedNinjas) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(clanName)) + .ReturnsAsync(true) + .Verifiable(); + + // Act + var result = await ServiceUnderTest.ReadAllInClanAsync(clanName); + + // Assert + Assert.Same(expectedNinjas, result); + NinjaRepositoryMock + .Verify(x => x.ReadAllInClanAsync(clanName), Times.Once); + ClanServiceMock + .Verify(x => x.IsClanExistsAsync(clanName), Times.Once); + } + + [Fact] + public async void Should_throw_ClanNotFoundException_when_clan_does_not_exist() + { + // Arrange + var unexistingClanName = "Some clan name"; + NinjaRepositoryMock + .Setup(x => x.ReadAllInClanAsync(unexistingClanName)) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(unexistingClanName)) + .ReturnsAsync(false) + .Verifiable(); + + // Act & Assert + await Assert.ThrowsAsync(() => ServiceUnderTest.ReadAllInClanAsync(unexistingClanName)); + + NinjaRepositoryMock + .Verify(x => x.ReadAllInClanAsync(unexistingClanName), Times.Never); + ClanServiceMock + .Verify(x => x.IsClanExistsAsync(unexistingClanName), Times.Once); + } + } + + public class ReadOneAsync : NinjaServiceTest + { + [Fact] + public async void Should_return_OkObjectResult_with_a_Ninja() + { + // Arrange + var clanName = "Some clan name"; + var ninjaKey = "Some ninja key"; + var expectedNinja = new Ninja { Name = "Test Ninja 1" }; + NinjaRepositoryMock + .Setup(x => x.ReadOneAsync(clanName, ninjaKey)) + .ReturnsAsync(expectedNinja); + + // Act + var result = await ServiceUnderTest.ReadOneAsync(clanName, ninjaKey); + + // Assert + Assert.Same(expectedNinja, result); + } + + [Fact] + public async void Should_throw_NinjaNotFoundException_when_ninja_does_not_exist() + { + // Arrange + var unexistingClanName = "Some clan name"; + var unexistingNinjaKey = "Some ninja key"; + NinjaRepositoryMock + .Setup(x => x.ReadOneAsync(unexistingClanName, unexistingNinjaKey)) + .ReturnsAsync(default(Ninja)); + + // Act & Assert + await Assert.ThrowsAsync(() => ServiceUnderTest.ReadOneAsync(unexistingClanName, unexistingNinjaKey)); + } + } + + public class CreateAsync : NinjaServiceTest + { + [Fact] + public async void Should_create_and_return_the_created_Ninja() + { + // Arrange + const string clanName = "Some clan name"; + var expectedNinja = new Ninja { Clan = new Clan { Name = clanName } }; + NinjaRepositoryMock + .Setup(x => x.CreateAsync(expectedNinja)) + .ReturnsAsync(expectedNinja) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(clanName)) + .ReturnsAsync(true); + + // Act + var result = await ServiceUnderTest.CreateAsync(expectedNinja); + + // Assert + Assert.Same(expectedNinja, result); + NinjaRepositoryMock.Verify(x => x.CreateAsync(expectedNinja), Times.Once); + } + + [Fact] + public async void Should_throw_a_ClanNotFoundException_when_clan_does_not_exist() + { + const string clanName = "Some clan name"; + var expectedNinja = new Ninja { Clan = new Clan { Name = clanName } }; + NinjaRepositoryMock + .Setup(x => x.CreateAsync(expectedNinja)) + .ReturnsAsync(expectedNinja) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(clanName)) + .ReturnsAsync(false); + + // Act & Assert + await Assert.ThrowsAsync(() => ServiceUnderTest.CreateAsync(expectedNinja)); + + // Make sure CreateAsync is never called + NinjaRepositoryMock.Verify(x => x.CreateAsync(expectedNinja), Times.Never); + } + } + + public class UpdateAsync : NinjaServiceTest + { + [Fact] + public async void Should_update_and_return_the_updated_Ninja() + { + // Arrange + const string ninjaKey = "Some key"; + const string clanKey = "Some clan"; + var expectedNinja = new Ninja + { + Key = ninjaKey, + Clan = new Clan { Name = clanKey } + }; + NinjaRepositoryMock + .Setup(x => x.ReadOneAsync(clanKey, ninjaKey)) + .ReturnsAsync(expectedNinja); + NinjaRepositoryMock + .Setup(x => x.UpdateAsync(expectedNinja)) + .ReturnsAsync(expectedNinja) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(clanKey)) + .ReturnsAsync(true); + + // Act + var result = await ServiceUnderTest.UpdateAsync(expectedNinja); + + // Assert + Assert.Same(expectedNinja, result); + NinjaRepositoryMock.Verify(x => x.UpdateAsync(expectedNinja), Times.Once); + } + + [Fact] + public async void Should_throw_NinjaNotFoundException_when_ninja_does_not_exist() + { + // Arrange + const string ninjaKey = "SomeKey"; + const string clanKey = "Some clan"; + var unexistingNinja = new Ninja { Key = ninjaKey, Clan = new Clan { Name = clanKey } }; + NinjaRepositoryMock + .Setup(x => x.UpdateAsync(unexistingNinja)) + .Verifiable(); + NinjaRepositoryMock + .Setup(x => x.ReadOneAsync(clanKey, ninjaKey)) + .ReturnsAsync(default(Ninja)) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(clanKey)) + .ReturnsAsync(true); + + // Act & Assert + await Assert.ThrowsAsync(() => ServiceUnderTest.UpdateAsync(unexistingNinja)); + + // Make sure UpdateAsync is never hit + NinjaRepositoryMock + .Verify(x => x.UpdateAsync(unexistingNinja), Times.Never); + + // Make sure we read the ninja from the repository before attempting an update. + NinjaRepositoryMock + .Verify(x => x.ReadOneAsync(clanKey, ninjaKey), Times.Once); + } + + [Fact] + public async void Should_throw_a_ClanNotFoundException_when_clan_does_not_exist() + { + // Arrange + const string ninjaKey = "SomeKey"; + const string clanKey = "Some clan"; + var unexistingNinja = new Ninja { Key = ninjaKey, Clan = new Clan { Name = clanKey } }; + NinjaRepositoryMock + .Setup(x => x.UpdateAsync(unexistingNinja)) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(clanKey)) + .ReturnsAsync(false); + + // Act & Assert + await Assert.ThrowsAsync(() => ServiceUnderTest.UpdateAsync(unexistingNinja)); + + // Make sure UpdateAsync is never called + NinjaRepositoryMock + .Verify(x => x.UpdateAsync(unexistingNinja), Times.Never); + } + } + + public class DeleteAsync : NinjaServiceTest + { + [Fact] + public async void Should_delete_and_return_the_deleted_Ninja() + { + // Arrange + var clanName = "My clan"; + var ninjaKey = "Some key"; + var expectedNinja = new Ninja { Name = "Test Ninja 1" }; + NinjaRepositoryMock + .Setup(x => x.DeleteAsync(clanName, ninjaKey)) + .ReturnsAsync(expectedNinja) + .Verifiable(); + NinjaRepositoryMock + .Setup(x => x.ReadOneAsync(clanName, ninjaKey)) + .ReturnsAsync(expectedNinja); + + // Act + var result = await ServiceUnderTest.DeleteAsync(clanName, ninjaKey); + + // Assert + Assert.Same(expectedNinja, result); + NinjaRepositoryMock.Verify(x => x.DeleteAsync(clanName, ninjaKey), Times.Once); + } + + [Fact] + public async void Should_throw_NinjaNotFoundException_when_ninja_does_not_exist() + { + // Arrange + const string clanName = "Some clan name"; + const string ninjaKey = "Some ninja key"; + + NinjaRepositoryMock + .Setup(x => x.DeleteAsync(clanName, ninjaKey)) + .Verifiable(); + NinjaRepositoryMock + .Setup(x => x.ReadOneAsync(clanName, ninjaKey)) + .ReturnsAsync(default(Ninja)) + .Verifiable(); + + // Act & Assert + await Assert.ThrowsAsync(() => ServiceUnderTest.DeleteAsync(clanName, ninjaKey)); + + // Make sure UpdateAsync is never hit + NinjaRepositoryMock + .Verify(x => x.DeleteAsync(clanName, ninjaKey), Times.Never); + + // Make sure we read the ninja from the repository before attempting an update. + NinjaRepositoryMock + .Verify(x => x.ReadOneAsync(clanName, ninjaKey), Times.Once); + } + } + } +} \ No newline at end of file diff --git a/8. NinjaApi - NinjaRepository/README.md b/8. NinjaApi - NinjaRepository/README.md deleted file mode 100644 index 2288af9..0000000 --- a/8. NinjaApi - NinjaRepository/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Dependency Injection -This project contains the code sample of the -[Design Patterns: Asp.Net Core Web API, services, and repositories | Part 8: the NinjaRepository, Azure table storage and the ForEvolve Framework](http://www.forevolve.com/en/articles/2017/09/07/design-patterns-web-api-service-and-repository-part-8/) -article. \ No newline at end of file diff --git a/9. NinjaApi - NinjaMappingService/ForEvolve.Blog.Samples.NinjaApi.sln b/9. NinjaApi - NinjaMappingService/ForEvolve.Blog.Samples.NinjaApi.sln new file mode 100644 index 0000000..48f81a9 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/ForEvolve.Blog.Samples.NinjaApi.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26711.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{23BF447F-B872-4D4F-8F28-D443072AE93E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{2F55FE43-6EA6-4A7E-B70B-2E8267478F29}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ForEvolve.Blog.Samples.NinjaApi", "src\ForEvolve.Blog.Samples.NinjaApi\ForEvolve.Blog.Samples.NinjaApi.csproj", "{DD219D97-6BF6-4EE5-9E35-13185F4FA261}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ForEvolve.Blog.Samples.NinjaApi.Tests", "test\ForEvolve.Blog.Samples.NinjaApi.Tests\ForEvolve.Blog.Samples.NinjaApi.Tests.csproj", "{6705EB4C-3DF6-4385-AEAB-3EE2FE074E05}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ForEvolve.Blog.Samples.NinjaApi.IntegrationTests", "test\ForEvolve.Blog.Samples.NinjaApi.IntegrationTests\ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj", "{89C4A3D5-7272-4EC7-AC91-89ED8C1D00EA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DD219D97-6BF6-4EE5-9E35-13185F4FA261}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD219D97-6BF6-4EE5-9E35-13185F4FA261}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD219D97-6BF6-4EE5-9E35-13185F4FA261}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DD219D97-6BF6-4EE5-9E35-13185F4FA261}.Release|Any CPU.Build.0 = Release|Any CPU + {6705EB4C-3DF6-4385-AEAB-3EE2FE074E05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6705EB4C-3DF6-4385-AEAB-3EE2FE074E05}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6705EB4C-3DF6-4385-AEAB-3EE2FE074E05}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6705EB4C-3DF6-4385-AEAB-3EE2FE074E05}.Release|Any CPU.Build.0 = Release|Any CPU + {89C4A3D5-7272-4EC7-AC91-89ED8C1D00EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {89C4A3D5-7272-4EC7-AC91-89ED8C1D00EA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {89C4A3D5-7272-4EC7-AC91-89ED8C1D00EA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {89C4A3D5-7272-4EC7-AC91-89ED8C1D00EA}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {DD219D97-6BF6-4EE5-9E35-13185F4FA261} = {23BF447F-B872-4D4F-8F28-D443072AE93E} + {6705EB4C-3DF6-4385-AEAB-3EE2FE074E05} = {2F55FE43-6EA6-4A7E-B70B-2E8267478F29} + {89C4A3D5-7272-4EC7-AC91-89ED8C1D00EA} = {2F55FE43-6EA6-4A7E-B70B-2E8267478F29} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {47DBF882-4F3A-4C9F-95CC-1286279CC35B} + EndGlobalSection +EndGlobal diff --git a/9. NinjaApi - NinjaMappingService/README.md b/9. NinjaApi - NinjaMappingService/README.md new file mode 100644 index 0000000..bdb7438 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/README.md @@ -0,0 +1,4 @@ +# Dependency Injection +This project contains the code sample of the +[Design Patterns: Asp.Net Core Web API, services, and repositories | Part 9: the NinjaMappingService](http://www.forevolve.com/en/articles/2017/09/08/design-patterns-web-api-service-and-repository-part-9/) +article. \ No newline at end of file diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/ClansController.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/ClansController.cs new file mode 100644 index 0000000..4e3d49d --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/ClansController.cs @@ -0,0 +1,29 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Services; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Controllers +{ + [Route("v1/[controller]")] + public class ClansController : Controller + { + private readonly IClanService _clanService; + + public ClansController(IClanService clanService) + { + _clanService = clanService ?? throw new ArgumentNullException(nameof(clanService)); + } + + [HttpGet] + [ProducesResponseType(typeof(IEnumerable), 200)] + public async Task ReadAllAsync() + { + var allClans = await _clanService.ReadAllAsync(); + return Ok(allClans); + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/NinjaController.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/NinjaController.cs new file mode 100644 index 0000000..7f6d7eb --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Controllers/NinjaController.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using ForEvolve.Blog.Samples.NinjaApi.Models; +using Microsoft.AspNetCore.Http; +using ForEvolve.Blog.Samples.NinjaApi.Services; + +namespace ForEvolve.Blog.Samples.NinjaApi.Controllers +{ + [Route("v1/[controller]")] + public class NinjaController : Controller + { + private readonly INinjaService _ninjaService; + public NinjaController(INinjaService ninjaService) + { + _ninjaService = ninjaService ?? throw new ArgumentNullException(nameof(ninjaService)); + } + + [HttpGet] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + public async Task ReadAllAsync() + { + var allNinja = await _ninjaService.ReadAllAsync(); + return Ok(allNinja); + } + + [HttpGet("{clan}")] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task ReadAllInClanAsync(string clan) + { + try + { + var clanNinja = await _ninjaService.ReadAllInClanAsync(clan); + return Ok(clanNinja); + } + catch (ClanNotFoundException) + { + return NotFound(); + } + } + + [HttpGet("{clan}/{key}")] + [ProducesResponseType(typeof(Ninja), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task ReadOneAsync(string clan, string key) + { + try + { + var ninja = await _ninjaService.ReadOneAsync(clan, key); + return Ok(ninja); + } + catch (NinjaNotFoundException) + { + return NotFound(); + } + } + + [HttpPost] + [ProducesResponseType(typeof(Ninja), StatusCodes.Status201Created)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task CreateAsync([FromBody]Ninja ninja) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + var createdNinja = await _ninjaService.CreateAsync(ninja); + return CreatedAtAction( + nameof(ReadOneAsync), + new { clan = createdNinja.Clan.Name, key = createdNinja.Key }, + createdNinja + ); + } + + [HttpPut] + [ProducesResponseType(typeof(Ninja), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task UpdateAsync([FromBody]Ninja ninja) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + try + { + var updatedNinja = await _ninjaService.UpdateAsync(ninja); + return Ok(updatedNinja); + } + catch (NinjaNotFoundException) + { + return NotFound(); + } + } + + [HttpDelete("{clan}/{key}")] + [ProducesResponseType(typeof(Ninja), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task DeleteAsync(string clan, string key) + { + try + { + var deletedNinja = await _ninjaService.DeleteAsync(clan, key); + return Ok(deletedNinja); + } + catch (NinjaNotFoundException) + { + return NotFound(); + } + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/ClanNotFoundException.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/ClanNotFoundException.cs new file mode 100644 index 0000000..7d55c95 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/ClanNotFoundException.cs @@ -0,0 +1,17 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; + +namespace ForEvolve.Blog.Samples.NinjaApi +{ + public class ClanNotFoundException : NinjaApiException + { + public ClanNotFoundException(Clan clan) + : this(clan.Name) + { + } + + public ClanNotFoundException(string clanName) + : base($"Clan {clanName} was not found.") + { + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaApiException.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaApiException.cs new file mode 100644 index 0000000..ff81d64 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaApiException.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi +{ + public class NinjaApiException : Exception + { + public NinjaApiException() + { + } + + public NinjaApiException(string message) : base(message) + { + } + + public NinjaApiException(string message, Exception innerException) : base(message, innerException) + { + } + + protected NinjaApiException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaNotFoundException.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaNotFoundException.cs new file mode 100644 index 0000000..54c1d8d --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Exceptions/NinjaNotFoundException.cs @@ -0,0 +1,17 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; + +namespace ForEvolve.Blog.Samples.NinjaApi +{ + public class NinjaNotFoundException : NinjaApiException + { + public NinjaNotFoundException(Ninja ninja) + : base($"Ninja {ninja.Name} ({ninja.Key}) of clan {ninja.Clan.Name} was not found.") + { + } + + public NinjaNotFoundException(string clanName, string ninjaKey) + : base($"Ninja {ninjaKey} of clan {clanName} was not found.") + { + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj new file mode 100644 index 0000000..4c0cd14 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj @@ -0,0 +1,18 @@ + + + + netcoreapp2.0 + aspnet-ForEvolve.Blog.Samples.NinjaApi-F62B525A-ACF4-4C7C-BF23-1EB0F434DDE5 + Full + + + + + + + + + + + + diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/IMapper.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/IMapper.cs new file mode 100644 index 0000000..2628ecb --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/IMapper.cs @@ -0,0 +1,7 @@ +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public interface IMapper + { + TDestination Map(TSource entity); + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs new file mode 100644 index 0000000..138aac7 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs @@ -0,0 +1,30 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public class NinjaEntityEnumerableToNinjaMapper : IMapper, IEnumerable> + { + private readonly IMapper _ninjaEntityToNinjaMapper; + + public NinjaEntityEnumerableToNinjaMapper(IMapper ninjaEntityToNinjaMapper) + { + _ninjaEntityToNinjaMapper = ninjaEntityToNinjaMapper ?? throw new ArgumentNullException(nameof(ninjaEntityToNinjaMapper)); + } + + public IEnumerable Map(IEnumerable entities) + { + var count = entities.Count(); + var all = new Ninja[count]; + for (int i = 0; i < count; i++) + { + var entity = entities.ElementAt(i); + var ninja = _ninjaEntityToNinjaMapper.Map(entity); + all[i] = ninja; + } + return all; + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityToNinjaMapper.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityToNinjaMapper.cs new file mode 100644 index 0000000..745a6d9 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityToNinjaMapper.cs @@ -0,0 +1,19 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; + +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public class NinjaEntityToNinjaMapper : IMapper + { + public Ninja Map(NinjaEntity entity) + { + var ninja = new Ninja + { + Key = entity.RowKey, + Clan = new Clan { Name = entity.PartitionKey }, + Level = entity.Level, + Name = entity.Name + }; + return ninja; + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaToNinjaEntityMapper.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaToNinjaEntityMapper.cs new file mode 100644 index 0000000..a4546f4 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaToNinjaEntityMapper.cs @@ -0,0 +1,19 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; + +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public class NinjaToNinjaEntityMapper : IMapper + { + public NinjaEntity Map(Ninja ninja) + { + var entity = new NinjaEntity + { + PartitionKey = ninja.Clan.Name, + RowKey = ninja.Key, + Name = ninja.Name, + Level = ninja.Level + }; + return entity; + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Models/Clan.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Models/Clan.cs new file mode 100644 index 0000000..7b7c615 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Models/Clan.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Models +{ + public class Clan + { + public string Name { get; set; } + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Models/Ninja.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Models/Ninja.cs new file mode 100644 index 0000000..110e285 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Models/Ninja.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Models +{ + public class Ninja + { + public string Key { get; set; } + public Clan Clan { get; set; } + public string Name { get; set; } + public int Level { get; set; } + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Models/NinjaEntity.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Models/NinjaEntity.cs new file mode 100644 index 0000000..12906d9 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Models/NinjaEntity.cs @@ -0,0 +1,14 @@ +using Microsoft.WindowsAzure.Storage.Table; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Models +{ + public class NinjaEntity : TableEntity + { + public string Name { get; set; } + public int Level { get; set; } + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Program.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Program.cs new file mode 100644 index 0000000..88c9273 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Program.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace ForEvolve.Blog.Samples.NinjaApi +{ + public class Program + { + public static void Main(string[] args) + { + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup() + .Build(); + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Properties/launchSettings.json b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Properties/launchSettings.json new file mode 100644 index 0000000..5285189 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:2439/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "v1/ninja", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "ForEvolve.Blog.Samples.NinjaApi": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "api/values", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:2440/" + } + } +} \ No newline at end of file diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/ClanRepository.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/ClanRepository.cs new file mode 100644 index 0000000..c3f5176 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/ClanRepository.cs @@ -0,0 +1,45 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System; +using System.Linq; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Repositories +{ + public class ClanRepository : IClanRepository + { + private readonly List _clans; + + public ClanRepository(IEnumerable clans) + { + if (clans == null) { throw new ArgumentNullException(nameof(clans)); } + _clans = new List(clans); + } + + public Task> ReadAllAsync() + { + return Task.FromResult(_clans.AsEnumerable()); + } + + public Task ReadOneAsync(string clanName) + { + var clan = _clans.FirstOrDefault(c => c.Name == clanName); + return Task.FromResult(clan); + } + + public Task CreateAsync(Clan clan) + { + throw new NotSupportedException(); + } + + public Task UpdateAsync(Clan clan) + { + throw new NotSupportedException(); + } + + public Task DeleteAsync(string clanName) + { + throw new NotSupportedException(); + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/IClanRepository.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/IClanRepository.cs new file mode 100644 index 0000000..e2e41ed --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/IClanRepository.cs @@ -0,0 +1,16 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Repositories +{ + public interface IClanRepository + { + Task> ReadAllAsync(); + Task ReadOneAsync(string clanName); + Task CreateAsync(Clan clan); + Task UpdateAsync(Clan clan); + Task DeleteAsync(string clanName); + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/INinjaRepository.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/INinjaRepository.cs new file mode 100644 index 0000000..0075b92 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/INinjaRepository.cs @@ -0,0 +1,18 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Repositories +{ + public interface INinjaRepository + { + Task> ReadAllAsync(); + Task> ReadAllInClanAsync(string clanName); + Task ReadOneAsync(string clanName, string ninjaKey); + Task CreateAsync(Ninja ninja); + Task UpdateAsync(Ninja ninja); + Task DeleteAsync(string clanName, string ninjaKey); + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/ClanService.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/ClanService.cs new file mode 100644 index 0000000..d6b6118 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/ClanService.cs @@ -0,0 +1,49 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Repositories; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public class ClanService : IClanService + { + private IClanRepository _clanRepository; + + public ClanService(IClanRepository clanRepository) + { + _clanRepository = clanRepository ?? throw new ArgumentNullException(nameof(clanRepository)); + } + + public Task> ReadAllAsync() + { + return _clanRepository.ReadAllAsync(); + } + + public Task ReadOneAsync(string clanName) + { + return _clanRepository.ReadOneAsync(clanName); + } + + public async Task IsClanExistsAsync(string clanName) + { + var clan = await _clanRepository.ReadOneAsync(clanName); + return clan != null; + } + + public Task CreateAsync(Clan clan) + { + throw new NotSupportedException(); + } + + public Task UpdateAsync(Clan clan) + { + throw new NotSupportedException(); + } + + public Task DeleteAsync(string clanName) + { + throw new NotSupportedException(); + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/IClanService.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/IClanService.cs new file mode 100644 index 0000000..54843b9 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/IClanService.cs @@ -0,0 +1,17 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public interface IClanService + { + Task> ReadAllAsync(); + Task ReadOneAsync(string clanName); + Task IsClanExistsAsync(string clanName); + Task CreateAsync(Clan clan); + Task UpdateAsync(Clan clan); + Task DeleteAsync(string clanName); + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaMappingService.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaMappingService.cs new file mode 100644 index 0000000..5186991 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaMappingService.cs @@ -0,0 +1,13 @@ +using ForEvolve.Blog.Samples.NinjaApi.Mappers; +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public interface INinjaMappingService : IMapper, IMapper, IMapper, IEnumerable> + { + } +} + diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaService.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaService.cs new file mode 100644 index 0000000..841069d --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/INinjaService.cs @@ -0,0 +1,17 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public interface INinjaService + { + Task> ReadAllAsync(); + Task> ReadAllInClanAsync(string clanName); + Task ReadOneAsync(string clanName, string ninjaKey); + Task CreateAsync(Ninja ninja); + Task UpdateAsync(Ninja ninja); + Task DeleteAsync(string clanName, string ninjaKey); + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaMappingService.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaMappingService.cs new file mode 100644 index 0000000..25aefbf --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaMappingService.cs @@ -0,0 +1,40 @@ +using ForEvolve.Blog.Samples.NinjaApi.Mappers; +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System; +using System.Collections.Generic; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public class NinjaMappingService : INinjaMappingService + { + private readonly IMapper _ninjaToNinjaEntityMapper; + private readonly IMapper _ninjaEntityToNinjaMapper; + private readonly IMapper, IEnumerable> _ninjaEntityEnumerableToNinjaMapper; + + public NinjaMappingService( + IMapper ninjaToNinjaEntityMapper, + IMapper ninjaEntityToNinjaMapper, + IMapper, IEnumerable> ninjaEntityEnumerableToNinjaMapper + ) + { + _ninjaToNinjaEntityMapper = ninjaToNinjaEntityMapper ?? throw new ArgumentNullException(nameof(ninjaToNinjaEntityMapper)); + _ninjaEntityToNinjaMapper = ninjaEntityToNinjaMapper ?? throw new ArgumentNullException(nameof(ninjaEntityToNinjaMapper)); + _ninjaEntityEnumerableToNinjaMapper = ninjaEntityEnumerableToNinjaMapper ?? throw new ArgumentNullException(nameof(ninjaEntityEnumerableToNinjaMapper)); + } + + public NinjaEntity Map(Ninja entity) + { + return _ninjaToNinjaEntityMapper.Map(entity); + } + + public Ninja Map(NinjaEntity entity) + { + return _ninjaEntityToNinjaMapper.Map(entity); + } + + public IEnumerable Map(IEnumerable entities) + { + return _ninjaEntityEnumerableToNinjaMapper.Map(entities); + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaService.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaService.cs new file mode 100644 index 0000000..2e96b1f --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Services/NinjaService.cs @@ -0,0 +1,78 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Repositories; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public class NinjaService : INinjaService + { + private readonly INinjaRepository _ninjaRepository; + private readonly IClanService _clanService; + + public NinjaService(INinjaRepository ninjaRepository, IClanService clanService) + { + _ninjaRepository = ninjaRepository ?? throw new ArgumentNullException(nameof(ninjaRepository)); + _clanService = clanService ?? throw new ArgumentNullException(nameof(clanService)); + } + + public async Task CreateAsync(Ninja ninja) + { + await EnforceClanExistenceAsync(ninja.Clan.Name); + var createdNinja = await _ninjaRepository.CreateAsync(ninja); + return createdNinja; + } + + public async Task DeleteAsync(string clanName, string ninjaKey) + { + await EnforceNinjaExistenceAsync(clanName, ninjaKey); + var deletedNinja = await _ninjaRepository.DeleteAsync(clanName, ninjaKey); + return deletedNinja; + } + + public Task> ReadAllAsync() + { + return _ninjaRepository.ReadAllAsync(); + } + + public async Task> ReadAllInClanAsync(string clanName) + { + await EnforceClanExistenceAsync(clanName); + return await _ninjaRepository.ReadAllInClanAsync(clanName); + } + + public async Task ReadOneAsync(string clanName, string ninjaKey) + { + var ninja = await EnforceNinjaExistenceAsync(clanName, ninjaKey); + return ninja; + } + + public async Task UpdateAsync(Ninja ninja) + { + await EnforceClanExistenceAsync(ninja.Clan.Name); + await EnforceNinjaExistenceAsync(ninja.Clan.Name, ninja.Key); + var updatedNinja = await _ninjaRepository.UpdateAsync(ninja); + return updatedNinja; + } + + private async Task EnforceClanExistenceAsync(string clanName) + { + var clanExist = await _clanService.IsClanExistsAsync(clanName); + if (!clanExist) + { + throw new ClanNotFoundException(clanName); + } + } + + private async Task EnforceNinjaExistenceAsync(string clanName, string ninjaKey) + { + var remoteNinja = await _ninjaRepository.ReadOneAsync(clanName, ninjaKey); + if (remoteNinja == null) + { + throw new NinjaNotFoundException(clanName, ninjaKey); + } + return remoteNinja; + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs new file mode 100644 index 0000000..dcfa445 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.DependencyInjection.Extensions; +using ForEvolve.Blog.Samples.NinjaApi.Services; +using ForEvolve.Blog.Samples.NinjaApi.Repositories; +using ForEvolve.Blog.Samples.NinjaApi.Models; + +namespace ForEvolve.Blog.Samples.NinjaApi +{ + public class Startup + { + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton>(new Clan[]{ + new Clan { Name = "Iga" }, + new Clan { Name = "Kōga" }, + }); + services.AddMvc(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + app.ApplicationServices.GetService(); + app.UseMvc(); + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.Development.json b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.Development.json new file mode 100644 index 0000000..fa8ce71 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.Development.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.json b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.json new file mode 100644 index 0000000..26bb0ac --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/appsettings.json @@ -0,0 +1,15 @@ +{ + "Logging": { + "IncludeScopes": false, + "Debug": { + "LogLevel": { + "Default": "Warning" + } + }, + "Console": { + "LogLevel": { + "Default": "Warning" + } + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/BaseHttpTest.cs b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/BaseHttpTest.cs new file mode 100644 index 0000000..e314434 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/BaseHttpTest.cs @@ -0,0 +1,59 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Text; + +namespace ForEvolve.Blog.Samples.NinjaApi.IntegrationTests +{ + public abstract class BaseHttpTest : IDisposable + { + protected TestServer Server { get; } + protected HttpClient Client { get; } + + protected virtual Uri BaseAddress => new Uri("http://localhost"); + protected virtual string Environment => "Development"; + + public BaseHttpTest() + { + var builder = new WebHostBuilder() + .UseEnvironment(Environment) + .ConfigureServices(ConfigureServices) + .UseStartup(); + + Server = new TestServer(builder); + Client = Server.CreateClient(); + Client.BaseAddress = BaseAddress; + } + + protected virtual void ConfigureServices(IServiceCollection services) + { + } + + #region IDisposable Support + + private bool disposedValue = false; + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + Client.Dispose(); + Server.Dispose(); + } + disposedValue = true; + } + } + + public void Dispose() + { + Dispose(true); + } + + #endregion + } +} diff --git a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ClansControllerTest.cs b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ClansControllerTest.cs new file mode 100644 index 0000000..b1f2950 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ClansControllerTest.cs @@ -0,0 +1,51 @@ +using System; +using Xunit; +using Microsoft.AspNetCore.TestHost; +using System.Net.Http; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using System.Collections.Generic; +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System.Threading.Tasks; +using System.Linq; + +namespace ForEvolve.Blog.Samples.NinjaApi.IntegrationTests +{ + public class ClansControllerTest : BaseHttpTest + { + public class ReadAllAsync : ClansControllerTest + { + private IEnumerable Clans => new Clan[] { + new Clan { Name = "My clan" }, + new Clan { Name = "Your clan" }, + new Clan { Name = "His clan" } + }; + + protected override void ConfigureServices(IServiceCollection services) + { + services.AddSingleton(Clans); + } + + [Fact] + public async Task Should_return_the_default_clans() + { + // Arrange + var expectedNumberOfClans = Clans.Count(); + + // Act + var result = await Client.GetAsync("v1/clans"); + + // Assert + result.EnsureSuccessStatusCode(); + var clans = await result.Content.ReadAsJsonObjectAsync(); + Assert.NotNull(clans); + Assert.Equal(expectedNumberOfClans, clans.Length); + Assert.Collection(clans, + clan => Assert.Equal(Clans.ElementAt(0).Name, clans[0].Name), + clan => Assert.Equal(Clans.ElementAt(1).Name, clans[1].Name), + clan => Assert.Equal(Clans.ElementAt(2).Name, clans[2].Name) + ); + } + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj new file mode 100644 index 0000000..8ad286b --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp2.0 + + false + + + + + + + + + + + + + + diff --git a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs new file mode 100644 index 0000000..637653f --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs @@ -0,0 +1,34 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; +using Microsoft.Extensions.DependencyInjection; +using System.Linq; + +namespace ForEvolve.Blog.Samples.NinjaApi.IntegrationTests +{ + public class StartupTest : BaseHttpTest + { + public class ServiceProvider : StartupTest + { + [Fact] + public void Should_return_both_Iga_and_Kōga_clans() + { + // Arrange + var serviceProvider = Server.Host.Services; + + // Act + var clans = serviceProvider.GetService>(); + + // Assert + Assert.NotNull(clans); + Assert.Equal(2, clans.Count()); + Assert.Collection(clans, + clan => Assert.Equal("Iga", clan.Name), + clan => Assert.Equal("Kōga", clan.Name) + ); + } + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/ClansControllerTest.cs b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/ClansControllerTest.cs new file mode 100644 index 0000000..bd6cec4 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/ClansControllerTest.cs @@ -0,0 +1,47 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using Microsoft.AspNetCore.Mvc; +using System; +using Xunit; +using Moq; +using ForEvolve.Blog.Samples.NinjaApi.Services; + +namespace ForEvolve.Blog.Samples.NinjaApi.Controllers +{ + public class ClansControllerTest + { + protected ClansController ControllerUnderTest { get; } + protected Mock ClanServiceMock { get; } + + public ClansControllerTest() + { + ClanServiceMock = new Mock(); + ControllerUnderTest = new ClansController(ClanServiceMock.Object); + } + + + public class ReadAllAsync : ClansControllerTest + { + [Fact] + public async void Should_return_OkObjectResult_with_clans() + { + // Arrange + var expectedClans = new Clan[] + { + new Clan { Name = "Test clan 1" }, + new Clan { Name = "Test clan 2" }, + new Clan { Name = "Test clan 3" } + }; + ClanServiceMock + .Setup(x => x.ReadAllAsync()) + .ReturnsAsync(expectedClans); + + // Act + var result = await ControllerUnderTest.ReadAllAsync(); + + // Assert + var okResult = Assert.IsType(result); + Assert.Same(expectedClans, okResult.Value); + } + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/NinjaControllerTest.cs b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/NinjaControllerTest.cs new file mode 100644 index 0000000..3fec6d2 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Controllers/NinjaControllerTest.cs @@ -0,0 +1,270 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Services; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Moq; +using System; +using System.Collections.Generic; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Controllers +{ + public class NinjaControllerTest + { + protected NinjaController ControllerUnderTest { get; } + protected Mock NinjaServiceMock { get; } + + public NinjaControllerTest() + { + NinjaServiceMock = new Mock(); + ControllerUnderTest = new NinjaController(NinjaServiceMock.Object); + } + + public class ReadAllAsync : NinjaControllerTest + { + [Fact] + public async void Should_return_OkObjectResult_with_all_Ninja() + { + // Arrange + var expectedNinjas = new Ninja[] + { + new Ninja { Name = "Test Ninja 1" }, + new Ninja { Name = "Test Ninja 2" }, + new Ninja { Name = "Test Ninja 3" } + }; + NinjaServiceMock + .Setup(x => x.ReadAllAsync()) + .ReturnsAsync(expectedNinjas); + + // Act + var result = await ControllerUnderTest.ReadAllAsync(); + + // Assert + var okResult = Assert.IsType(result); + Assert.Same(expectedNinjas, okResult.Value); + } + } + + public class ReadAllInClanAsync : NinjaControllerTest + { + [Fact] + public async void Should_return_OkObjectResult_with_all_Ninja_in_Clan() + { + // Arrange + var clanName = "Some clan name"; + var expectedNinjas = new Ninja[] + { + new Ninja { Name = "Test Ninja 1" }, + new Ninja { Name = "Test Ninja 2" }, + new Ninja { Name = "Test Ninja 3" } + }; + NinjaServiceMock + .Setup(x => x.ReadAllInClanAsync(clanName)) + .ReturnsAsync(expectedNinjas); + + // Act + var result = await ControllerUnderTest.ReadAllInClanAsync(clanName); + + // Assert + var okResult = Assert.IsType(result); + Assert.Same(expectedNinjas, okResult.Value); + } + + [Fact] + public async void Should_return_NotFoundResult_when_ClanNotFoundException_is_thrown() + { + // Arrange + var unexistingClanName = "Some clan name"; + NinjaServiceMock + .Setup(x => x.ReadAllInClanAsync(unexistingClanName)) + .ThrowsAsync(new ClanNotFoundException(unexistingClanName)); + + // Act + var result = await ControllerUnderTest.ReadAllInClanAsync(unexistingClanName); + + // Assert + Assert.IsType(result); + } + } + + public class ReadOneAsync : NinjaControllerTest + { + [Fact] + public async void Should_return_OkObjectResult_with_a_Ninja() + { + // Arrange + var clanName = "Some clan name"; + var ninjaKey = "Some ninja key"; + var expectedNinja = new Ninja { Name = "Test Ninja 1" }; + NinjaServiceMock + .Setup(x => x.ReadOneAsync(clanName, ninjaKey)) + .ReturnsAsync(expectedNinja); + + // Act + var result = await ControllerUnderTest.ReadOneAsync(clanName, ninjaKey); + + // Assert + var okResult = Assert.IsType(result); + Assert.Same(expectedNinja, okResult.Value); + } + + [Fact] + public async void Should_return_NotFoundResult_when_NinjaNotFoundException_is_thrown() + { + // Arrange + var unexistingClanName = "Some clan name"; + var unexistingNinjaKey = "Some ninja key"; + NinjaServiceMock + .Setup(x => x.ReadOneAsync(unexistingClanName, unexistingNinjaKey)) + .ThrowsAsync(new NinjaNotFoundException(unexistingClanName, unexistingNinjaKey)); + + // Act + var result = await ControllerUnderTest.ReadOneAsync(unexistingClanName, unexistingNinjaKey); + + // Assert + Assert.IsType(result); + } + } + + public class CreateAsync : NinjaControllerTest + { + [Fact] + public async void Should_return_CreatedAtActionResult_with_the_created_Ninja() + { + // Arrange + var expectedNinjaKey = "SomeNinjaKey"; + var expectedClanName = "My Clan"; + var expectedCreatedAtActionName = nameof(NinjaController.ReadOneAsync); + var expectedNinja = new Ninja { Name = "Test Ninja 1", Clan = new Clan { Name = expectedClanName } }; + NinjaServiceMock + .Setup(x => x.CreateAsync(expectedNinja)) + .ReturnsAsync(() => + { + expectedNinja.Key = expectedNinjaKey; + return expectedNinja; + }); + + // Act + var result = await ControllerUnderTest.CreateAsync(expectedNinja); + + // Assert + var createdResult = Assert.IsType(result); + Assert.Same(expectedNinja, createdResult.Value); + Assert.Equal(expectedCreatedAtActionName, createdResult.ActionName); + Assert.Equal( + expectedNinjaKey, + createdResult.RouteValues.GetValueOrDefault("key") + ); + Assert.Equal( + expectedClanName, + createdResult.RouteValues.GetValueOrDefault("clan") + ); + } + + [Fact] + public async void Should_return_BadRequestResult() + { + // Arrange + var ninja = new Ninja { Name = "Test Ninja 1" }; + ControllerUnderTest.ModelState.AddModelError("Key", "Some error"); + + // Act + var result = await ControllerUnderTest.CreateAsync(ninja); + + // Assert + var badRequestResult = Assert.IsType(result); + Assert.IsType(badRequestResult.Value); + } + } + + public class UpdateAsync : NinjaControllerTest + { + [Fact] + public async void Should_return_OkObjectResult_with_the_updated_Ninja() + { + // Arrange + var expectedNinja = new Ninja { Name = "Test Ninja 1" }; + NinjaServiceMock + .Setup(x => x.UpdateAsync(expectedNinja)) + .ReturnsAsync(expectedNinja); + + // Act + var result = await ControllerUnderTest.UpdateAsync(expectedNinja); + + // Assert + var createdResult = Assert.IsType(result); + Assert.Same(expectedNinja, createdResult.Value); + } + + [Fact] + public async void Should_return_NotFoundResult_when_NinjaNotFoundException_is_thrown() + { + // Arrange + var unexistingNinja = new Ninja { Name = "Test Ninja 1", Clan = new Clan { Name = "Some clan" } }; + NinjaServiceMock + .Setup(x => x.UpdateAsync(unexistingNinja)) + .ThrowsAsync(new NinjaNotFoundException(unexistingNinja)); + + // Act + var result = await ControllerUnderTest.UpdateAsync(unexistingNinja); + + // Assert + Assert.IsType(result); + } + + [Fact] + public async void Should_return_BadRequestResult() + { + // Arrange + var ninja = new Ninja { Name = "Test Ninja 1" }; + ControllerUnderTest.ModelState.AddModelError("Key", "Some error"); + + // Act + var result = await ControllerUnderTest.UpdateAsync(ninja); + + // Assert + var badRequestResult = Assert.IsType(result); + Assert.IsType(badRequestResult.Value); + } + } + + public class DeleteAsync : NinjaControllerTest + { + [Fact] + public async void Should_return_OkObjectResult_with_the_deleted_Ninja() + { + // Arrange + var clanName = "My clan"; + var ninjaKey = "Some key"; + var expectedNinja = new Ninja { Name = "Test Ninja 1" }; + NinjaServiceMock + .Setup(x => x.DeleteAsync(clanName, ninjaKey)) + .ReturnsAsync(expectedNinja); + + // Act + var result = await ControllerUnderTest.DeleteAsync(clanName, ninjaKey); + + // Assert + var createdResult = Assert.IsType(result); + Assert.Same(expectedNinja, createdResult.Value); + } + + [Fact] + public async void Should_return_NotFoundResult_when_NinjaNotFoundException_is_thrown() + { + // Arrange + var unexistingClanName = "Some clan name"; + var unexistingNinjaKey = "Some ninja key"; + NinjaServiceMock + .Setup(x => x.DeleteAsync(unexistingClanName, unexistingNinjaKey)) + .ThrowsAsync(new NinjaNotFoundException(unexistingClanName, unexistingNinjaKey)); + + // Act + var result = await ControllerUnderTest.DeleteAsync(unexistingClanName, unexistingNinjaKey); + + // Assert + Assert.IsType(result); + } + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/ForEvolve.Blog.Samples.NinjaApi.Tests.csproj b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/ForEvolve.Blog.Samples.NinjaApi.Tests.csproj new file mode 100644 index 0000000..cf0b996 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/ForEvolve.Blog.Samples.NinjaApi.Tests.csproj @@ -0,0 +1,22 @@ + + + + netcoreapp2.0 + + false + + ForEvolve.Blog.Samples.NinjaApi + + + + + + + + + + + + + + diff --git a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs new file mode 100644 index 0000000..145e2a7 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs @@ -0,0 +1,45 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using Moq; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public class NinjaEntityEnumerableToNinjaMapperTest + { + protected NinjaEntityEnumerableToNinjaMapper MapperUnderTest { get; } + protected Mock> NinjaEntityToNinjaMapperMock { get; } + + public NinjaEntityEnumerableToNinjaMapperTest() + { + NinjaEntityToNinjaMapperMock = new Mock>(); + MapperUnderTest = new NinjaEntityEnumerableToNinjaMapper(NinjaEntityToNinjaMapperMock.Object); + } + + public class Map : NinjaEntityEnumerableToNinjaMapperTest + { + [Fact] + public void Should_delegate_mapping_to_the_sinlge_entity_mapper() + { + // Arrange + var ninja1 = new NinjaEntity(); + var ninja2 = new NinjaEntity(); + var ninjaEntities = new List { ninja1, ninja2 }; + + NinjaEntityToNinjaMapperMock + .Setup(x => x.Map(It.IsAny())) + .Returns(new Ninja()) + .Verifiable(); + + // Act + var result = MapperUnderTest.Map(ninjaEntities); + + // Assert + NinjaEntityToNinjaMapperMock.Verify(x => x.Map(ninja1), Times.Once); + NinjaEntityToNinjaMapperMock.Verify(x => x.Map(ninja2), Times.Once); + } + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityToNinjaMapperTest.cs b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityToNinjaMapperTest.cs new file mode 100644 index 0000000..699f0a4 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityToNinjaMapperTest.cs @@ -0,0 +1,41 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public class NinjaEntityToNinjaMapperTest + { + protected NinjaEntityToNinjaMapper MapperUnderTest { get; } + + public NinjaEntityToNinjaMapperTest() + { + MapperUnderTest = new NinjaEntityToNinjaMapper(); + } + + public class Map : NinjaEntityToNinjaMapperTest + { + [Fact] + public void Should_return_a_well_formatted_ninja() + { + // Arrange + var entity = new NinjaEntity + { + Level = 10, + Name = "Some fake name", + PartitionKey = "Some clan name", + RowKey = "Some ninja key" + }; + + // Act + var result = MapperUnderTest.Map(entity); + + // Assert + Assert.Equal(10, result.Level); + Assert.Equal("Some fake name", result.Name); + Assert.NotNull(result.Clan); + Assert.Equal("Some clan name", result.Clan.Name); + Assert.Equal("Some ninja key", result.Key); + } + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaToNinjaEntityMapperTest.cs b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaToNinjaEntityMapperTest.cs new file mode 100644 index 0000000..1a08e1c --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaToNinjaEntityMapperTest.cs @@ -0,0 +1,43 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public class NinjaToNinjaEntityMapperTest + { + protected NinjaToNinjaEntityMapper MapperUnderTest { get; } + + public NinjaToNinjaEntityMapperTest() + { + MapperUnderTest = new NinjaToNinjaEntityMapper(); + } + + public class Map : NinjaToNinjaEntityMapperTest + { + [Fact] + public void Should_return_a_well_formatted_entity() + { + // Arrange + var ninja = new Ninja + { + Key = "Some key", + Name = "Some name", + Level = 45, + Clan = new Clan { Name = "Super clan" } + }; + + // Act + var result = MapperUnderTest.Map(ninja); + + // Assert + Assert.Equal("Some key", result.RowKey); + Assert.Equal("Some name", result.Name); + Assert.Equal(45, result.Level); + Assert.Equal("Super clan", result.PartitionKey); + } + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/ClanRepositoryTest.cs b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/ClanRepositoryTest.cs new file mode 100644 index 0000000..ea77e7b --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/ClanRepositoryTest.cs @@ -0,0 +1,103 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Repositories +{ + public class ClanRepositoryTest + { + protected ClanRepository RepositoryUnderTest { get; } + protected Clan[] Clans { get; } + + public ClanRepositoryTest() + { + Clans = new Clan[] + { + new Clan { Name = "My clan" }, + new Clan { Name = "Your clan" }, + new Clan { Name = "His clan" } + }; + RepositoryUnderTest = new ClanRepository(Clans); + } + + public class ReadAllAsync : ClanRepositoryTest + { + [Fact] + public async Task Should_return_all_clans() + { + // Act + var result = await RepositoryUnderTest.ReadAllAsync(); + + // Assert + Assert.Collection(result, + clan => Assert.Same(Clans[0], clan), + clan => Assert.Same(Clans[1], clan), + clan => Assert.Same(Clans[2], clan) + ); + } + } + + public class ReadOneAsync : ClanRepositoryTest + { + [Fact] + public async Task Should_return_the_expected_clan() + { + // Arrange + var expectedClan = Clans[1]; + var expectedClanName = expectedClan.Name; + + // Act + var result = await RepositoryUnderTest.ReadOneAsync(expectedClanName); + + // Assert + Assert.Same(expectedClan, result); + } + + [Fact] + public async Task Should_return_null_if_the_clan_does_not_exist() + { + // Arrange + var unexistingClanName = "Unexisting clan"; + + // Act + var result = await RepositoryUnderTest.ReadOneAsync(unexistingClanName); + + // Assert + Assert.Null(result); + } + } + + public class CreateAsync : ClanRepositoryTest + { + [Fact] + public async Task Should_throw_a_NotSupportedException() + { + // Arrange, Act, Assert + var exception = await Assert.ThrowsAsync(() => RepositoryUnderTest.CreateAsync(null)); + } + } + + public class UpdateAsync : ClanRepositoryTest + { + [Fact] + public async Task Should_throw_a_NotSupportedException() + { + // Arrange, Act, Assert + var exception = await Assert.ThrowsAsync(() => RepositoryUnderTest.UpdateAsync(null)); + } + } + + public class DeleteAsync : ClanRepositoryTest + { + [Fact] + public async Task Should_throw_a_NotSupportedException() + { + // Arrange, Act, Assert + var exception = await Assert.ThrowsAsync(() => RepositoryUnderTest.DeleteAsync(null)); + } + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/ClanServiceTest.cs b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/ClanServiceTest.cs new file mode 100644 index 0000000..bba7c70 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/ClanServiceTest.cs @@ -0,0 +1,149 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Repositories; +using Moq; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public class ClanServiceTest + { + protected ClanService ServiceUnderTest { get; } + protected Mock ClanRepositoryMock { get; } + + public ClanServiceTest() + { + ClanRepositoryMock = new Mock(); + ServiceUnderTest = new ClanService(ClanRepositoryMock.Object); + } + + public class ReadAllAsync : ClanServiceTest + { + [Fact] + public async Task Should_return_all_clans() + { + // Arrange + var expectedClans = new ReadOnlyCollection(new List + { + new Clan { Name = "My Clan" }, + new Clan { Name = "Your Clan" }, + new Clan { Name = "His Clan" } + }); + ClanRepositoryMock + .Setup(x => x.ReadAllAsync()) + .ReturnsAsync(expectedClans); + + // Act + var result = await ServiceUnderTest.ReadAllAsync(); + + // Assert + Assert.Same(expectedClans, result); + } + } + + public class ReadOneAsync : ClanServiceTest + { + [Fact] + public async Task Should_return_the_expected_clan() + { + // Arrange + var clanName = "My Clan"; + var expectedClan = new Clan { Name = clanName }; + ClanRepositoryMock + .Setup(x => x.ReadOneAsync(clanName)) + .ReturnsAsync(expectedClan); + + // Act + var result = await ServiceUnderTest.ReadOneAsync(clanName); + + // Assert + Assert.Same(expectedClan, result); + } + + [Fact] + public async Task Should_return_null_if_the_clan_does_not_exist() + { + // Arrange + var clanName = "My Clan"; + ClanRepositoryMock + .Setup(x => x.ReadOneAsync(clanName)) + .ReturnsAsync(default(Clan)); + + // Act + var result = await ServiceUnderTest.ReadOneAsync(clanName); + + // Assert + Assert.Null(result); + } + } + + public class IsClanExistsAsync : ClanServiceTest + { + [Fact] + public async Task Should_return_true_if_the_clan_exist() + { + // Arrange + var clanName = "Your Clan"; + ClanRepositoryMock + .Setup(x => x.ReadOneAsync(clanName)) + .ReturnsAsync(new Clan()); + + // Act + var result = await ServiceUnderTest.IsClanExistsAsync(clanName); + + // Assert + Assert.True(result); + } + + [Fact] + public async Task Should_return_false_if_the_clan_does_not_exist() + { + // Arrange + var clanName = "Unexisting Clan"; + ClanRepositoryMock + .Setup(x => x.ReadOneAsync(clanName)) + .ReturnsAsync(default(Clan)); + + // Act + var result = await ServiceUnderTest.IsClanExistsAsync(clanName); + + // Assert + Assert.False(result); + } + } + + public class CreateAsync : ClanServiceTest + { + [Fact] + public async Task Should_throw_a_NotSupportedException() + { + // Arrange, Act, Assert + var exception = await Assert.ThrowsAsync(() => ServiceUnderTest.CreateAsync(null)); + } + } + + public class UpdateAsync : ClanServiceTest + { + [Fact] + public async Task Should_throw_a_NotSupportedException() + { + // Arrange, Act, Assert + var exception = await Assert.ThrowsAsync(() => ServiceUnderTest.UpdateAsync(null)); + } + } + + public class DeleteAsync : ClanServiceTest + { + [Fact] + public async Task Should_throw_a_NotSupportedException() + { + // Arrange, Act, Assert + var exception = await Assert.ThrowsAsync(() => ServiceUnderTest.DeleteAsync(null)); + } + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaMappingServiceTest.cs b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaMappingServiceTest.cs new file mode 100644 index 0000000..b0cb5df --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaMappingServiceTest.cs @@ -0,0 +1,81 @@ +using ForEvolve.Blog.Samples.NinjaApi.Mappers; +using ForEvolve.Blog.Samples.NinjaApi.Models; +using Moq; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public class NinjaMappingServiceTest + { + protected NinjaMappingService ServiceUnderTest { get; } + protected Mock> NinjaToNinjaEntityMapperMock { get; } + protected Mock> NinjaEntityToNinjaMapperMock { get; } + protected Mock, IEnumerable>> NinjaEntityEnumerableToNinjaMapperMock { get; } + + public NinjaMappingServiceTest() + { + NinjaToNinjaEntityMapperMock = new Mock>(); + NinjaEntityToNinjaMapperMock = new Mock>(); + NinjaEntityEnumerableToNinjaMapperMock = new Mock, IEnumerable>>(); + ServiceUnderTest = new NinjaMappingService( + NinjaToNinjaEntityMapperMock.Object, + NinjaEntityToNinjaMapperMock.Object, + NinjaEntityEnumerableToNinjaMapperMock.Object + ); + } + + [Fact] + public void Map_Ninja_to_NinjaEntity_should_delegate_to_NinjaToNinjaEntityMapper() + { + // Arrange + var ninja = new Ninja(); + var expectedEntity = new NinjaEntity(); + NinjaToNinjaEntityMapperMock + .Setup(x => x.Map(ninja)) + .Returns(expectedEntity); + + // Act + var result = ServiceUnderTest.Map(ninja); + + // Assert + Assert.Same(expectedEntity, result); + } + + [Fact] + public void Map_NinjaEntity_to_Ninja_should_delegate_to_NinjaEntityToNinjaMapper() + { + // Arrange + var ninjaEntity = new NinjaEntity(); + var expectedNinja = new Ninja(); + NinjaEntityToNinjaMapperMock + .Setup(x => x.Map(ninjaEntity)) + .Returns(expectedNinja); + + // Act + var result = ServiceUnderTest.Map(ninjaEntity); + + // Assert + Assert.Same(expectedNinja, result); + } + + [Fact] + public void Map_NinjaEntityEnumerable_to_NinjaEnumerable_should_delegate_to_NinjaEntityEnumerableToNinjaMapper() + { + // Arrange + var ninjaEntities = new List(); + var expectedNinja = new List(); + NinjaEntityEnumerableToNinjaMapperMock + .Setup(x => x.Map(ninjaEntities)) + .Returns(expectedNinja); + + // Act + var result = ServiceUnderTest.Map(ninjaEntities); + + // Assert + Assert.Same(expectedNinja, result); + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaServiceTest.cs b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaServiceTest.cs new file mode 100644 index 0000000..95180fe --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Services/NinjaServiceTest.cs @@ -0,0 +1,323 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Repositories; +using Microsoft.AspNetCore.Mvc; +using Moq; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Services +{ + public class NinjaServiceTest + { + protected NinjaService ServiceUnderTest { get; } + protected Mock NinjaRepositoryMock { get; } + protected Mock ClanServiceMock { get; } + + public NinjaServiceTest() + { + NinjaRepositoryMock = new Mock(); + ClanServiceMock = new Mock(); + ServiceUnderTest = new NinjaService(NinjaRepositoryMock.Object, ClanServiceMock.Object); + } + + public class ReadAllAsync : NinjaServiceTest + { + [Fact] + public async void Should_return_all_Ninja() + { + // Arrange + var expectedNinjas = new Ninja[] + { + new Ninja { Name = "Test Ninja 1" }, + new Ninja { Name = "Test Ninja 2" }, + new Ninja { Name = "Test Ninja 3" } + }; + NinjaRepositoryMock + .Setup(x => x.ReadAllAsync()) + .ReturnsAsync(expectedNinjas); + + // Act + var result = await ServiceUnderTest.ReadAllAsync(); + + // Assert + Assert.Same(expectedNinjas, result); + } + } + + public class ReadAllInClanAsync : NinjaServiceTest + { + [Fact] + public async void Should_return_all_Ninja_in_Clan() + { + // Arrange + var clanName = "Some clan name"; + var expectedNinjas = new Ninja[] + { + new Ninja { Name = "Test Ninja 1" }, + new Ninja { Name = "Test Ninja 2" }, + new Ninja { Name = "Test Ninja 3" } + }; + NinjaRepositoryMock + .Setup(x => x.ReadAllInClanAsync(clanName)) + .ReturnsAsync(expectedNinjas) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(clanName)) + .ReturnsAsync(true) + .Verifiable(); + + // Act + var result = await ServiceUnderTest.ReadAllInClanAsync(clanName); + + // Assert + Assert.Same(expectedNinjas, result); + NinjaRepositoryMock + .Verify(x => x.ReadAllInClanAsync(clanName), Times.Once); + ClanServiceMock + .Verify(x => x.IsClanExistsAsync(clanName), Times.Once); + } + + [Fact] + public async void Should_throw_ClanNotFoundException_when_clan_does_not_exist() + { + // Arrange + var unexistingClanName = "Some clan name"; + NinjaRepositoryMock + .Setup(x => x.ReadAllInClanAsync(unexistingClanName)) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(unexistingClanName)) + .ReturnsAsync(false) + .Verifiable(); + + // Act & Assert + await Assert.ThrowsAsync(() => ServiceUnderTest.ReadAllInClanAsync(unexistingClanName)); + + NinjaRepositoryMock + .Verify(x => x.ReadAllInClanAsync(unexistingClanName), Times.Never); + ClanServiceMock + .Verify(x => x.IsClanExistsAsync(unexistingClanName), Times.Once); + } + } + + public class ReadOneAsync : NinjaServiceTest + { + [Fact] + public async void Should_return_OkObjectResult_with_a_Ninja() + { + // Arrange + var clanName = "Some clan name"; + var ninjaKey = "Some ninja key"; + var expectedNinja = new Ninja { Name = "Test Ninja 1" }; + NinjaRepositoryMock + .Setup(x => x.ReadOneAsync(clanName, ninjaKey)) + .ReturnsAsync(expectedNinja); + + // Act + var result = await ServiceUnderTest.ReadOneAsync(clanName, ninjaKey); + + // Assert + Assert.Same(expectedNinja, result); + } + + [Fact] + public async void Should_throw_NinjaNotFoundException_when_ninja_does_not_exist() + { + // Arrange + var unexistingClanName = "Some clan name"; + var unexistingNinjaKey = "Some ninja key"; + NinjaRepositoryMock + .Setup(x => x.ReadOneAsync(unexistingClanName, unexistingNinjaKey)) + .ReturnsAsync(default(Ninja)); + + // Act & Assert + await Assert.ThrowsAsync(() => ServiceUnderTest.ReadOneAsync(unexistingClanName, unexistingNinjaKey)); + } + } + + public class CreateAsync : NinjaServiceTest + { + [Fact] + public async void Should_create_and_return_the_created_Ninja() + { + // Arrange + const string clanName = "Some clan name"; + var expectedNinja = new Ninja { Clan = new Clan { Name = clanName } }; + NinjaRepositoryMock + .Setup(x => x.CreateAsync(expectedNinja)) + .ReturnsAsync(expectedNinja) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(clanName)) + .ReturnsAsync(true); + + // Act + var result = await ServiceUnderTest.CreateAsync(expectedNinja); + + // Assert + Assert.Same(expectedNinja, result); + NinjaRepositoryMock.Verify(x => x.CreateAsync(expectedNinja), Times.Once); + } + + [Fact] + public async void Should_throw_a_ClanNotFoundException_when_clan_does_not_exist() + { + const string clanName = "Some clan name"; + var expectedNinja = new Ninja { Clan = new Clan { Name = clanName } }; + NinjaRepositoryMock + .Setup(x => x.CreateAsync(expectedNinja)) + .ReturnsAsync(expectedNinja) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(clanName)) + .ReturnsAsync(false); + + // Act & Assert + await Assert.ThrowsAsync(() => ServiceUnderTest.CreateAsync(expectedNinja)); + + // Make sure CreateAsync is never called + NinjaRepositoryMock.Verify(x => x.CreateAsync(expectedNinja), Times.Never); + } + } + + public class UpdateAsync : NinjaServiceTest + { + [Fact] + public async void Should_update_and_return_the_updated_Ninja() + { + // Arrange + const string ninjaKey = "Some key"; + const string clanKey = "Some clan"; + var expectedNinja = new Ninja + { + Key = ninjaKey, + Clan = new Clan { Name = clanKey } + }; + NinjaRepositoryMock + .Setup(x => x.ReadOneAsync(clanKey, ninjaKey)) + .ReturnsAsync(expectedNinja); + NinjaRepositoryMock + .Setup(x => x.UpdateAsync(expectedNinja)) + .ReturnsAsync(expectedNinja) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(clanKey)) + .ReturnsAsync(true); + + // Act + var result = await ServiceUnderTest.UpdateAsync(expectedNinja); + + // Assert + Assert.Same(expectedNinja, result); + NinjaRepositoryMock.Verify(x => x.UpdateAsync(expectedNinja), Times.Once); + } + + [Fact] + public async void Should_throw_NinjaNotFoundException_when_ninja_does_not_exist() + { + // Arrange + const string ninjaKey = "SomeKey"; + const string clanKey = "Some clan"; + var unexistingNinja = new Ninja { Key = ninjaKey, Clan = new Clan { Name = clanKey } }; + NinjaRepositoryMock + .Setup(x => x.UpdateAsync(unexistingNinja)) + .Verifiable(); + NinjaRepositoryMock + .Setup(x => x.ReadOneAsync(clanKey, ninjaKey)) + .ReturnsAsync(default(Ninja)) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(clanKey)) + .ReturnsAsync(true); + + // Act & Assert + await Assert.ThrowsAsync(() => ServiceUnderTest.UpdateAsync(unexistingNinja)); + + // Make sure UpdateAsync is never hit + NinjaRepositoryMock + .Verify(x => x.UpdateAsync(unexistingNinja), Times.Never); + + // Make sure we read the ninja from the repository before attempting an update. + NinjaRepositoryMock + .Verify(x => x.ReadOneAsync(clanKey, ninjaKey), Times.Once); + } + + [Fact] + public async void Should_throw_a_ClanNotFoundException_when_clan_does_not_exist() + { + // Arrange + const string ninjaKey = "SomeKey"; + const string clanKey = "Some clan"; + var unexistingNinja = new Ninja { Key = ninjaKey, Clan = new Clan { Name = clanKey } }; + NinjaRepositoryMock + .Setup(x => x.UpdateAsync(unexistingNinja)) + .Verifiable(); + ClanServiceMock + .Setup(x => x.IsClanExistsAsync(clanKey)) + .ReturnsAsync(false); + + // Act & Assert + await Assert.ThrowsAsync(() => ServiceUnderTest.UpdateAsync(unexistingNinja)); + + // Make sure UpdateAsync is never called + NinjaRepositoryMock + .Verify(x => x.UpdateAsync(unexistingNinja), Times.Never); + } + } + + public class DeleteAsync : NinjaServiceTest + { + [Fact] + public async void Should_delete_and_return_the_deleted_Ninja() + { + // Arrange + var clanName = "My clan"; + var ninjaKey = "Some key"; + var expectedNinja = new Ninja { Name = "Test Ninja 1" }; + NinjaRepositoryMock + .Setup(x => x.DeleteAsync(clanName, ninjaKey)) + .ReturnsAsync(expectedNinja) + .Verifiable(); + NinjaRepositoryMock + .Setup(x => x.ReadOneAsync(clanName, ninjaKey)) + .ReturnsAsync(expectedNinja); + + // Act + var result = await ServiceUnderTest.DeleteAsync(clanName, ninjaKey); + + // Assert + Assert.Same(expectedNinja, result); + NinjaRepositoryMock.Verify(x => x.DeleteAsync(clanName, ninjaKey), Times.Once); + } + + [Fact] + public async void Should_throw_NinjaNotFoundException_when_ninja_does_not_exist() + { + // Arrange + const string clanName = "Some clan name"; + const string ninjaKey = "Some ninja key"; + + NinjaRepositoryMock + .Setup(x => x.DeleteAsync(clanName, ninjaKey)) + .Verifiable(); + NinjaRepositoryMock + .Setup(x => x.ReadOneAsync(clanName, ninjaKey)) + .ReturnsAsync(default(Ninja)) + .Verifiable(); + + // Act & Assert + await Assert.ThrowsAsync(() => ServiceUnderTest.DeleteAsync(clanName, ninjaKey)); + + // Make sure UpdateAsync is never hit + NinjaRepositoryMock + .Verify(x => x.DeleteAsync(clanName, ninjaKey), Times.Never); + + // Make sure we read the ninja from the repository before attempting an update. + NinjaRepositoryMock + .Verify(x => x.ReadOneAsync(clanName, ninjaKey), Times.Once); + } + } + } +} \ No newline at end of file From 9c0265655c6acbdbbaddddb1c2ac578ed382843f Mon Sep 17 00:00:00 2001 From: Carl-Hugo Marcotte Date: Fri, 25 Aug 2017 01:55:17 -0400 Subject: [PATCH 02/11] Updated part 10 code --- .../Repositories/NinjaRepository.cs | 66 ++++++ .../Repositories/NinjaRepositoryTest.cs | 222 ++++++++++++++++++ 2 files changed, 288 insertions(+) create mode 100644 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/NinjaRepository.cs create mode 100644 10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/NinjaRepositoryTest.cs diff --git a/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/NinjaRepository.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/NinjaRepository.cs new file mode 100644 index 0000000..01e5210 --- /dev/null +++ b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/NinjaRepository.cs @@ -0,0 +1,66 @@ +using ForEvolve.Azure.Storage.Table; +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Services; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ForEvolve.Blog.Samples.NinjaApi.Repositories +{ + public class NinjaRepository : INinjaRepository + { + private readonly INinjaMappingService _ninjaMappingService; + private readonly ITableStorageRepository _ninjaEntityTableStorageRepository; + + public NinjaRepository(INinjaMappingService ninjaMappingService, ITableStorageRepository ninjaEntityTableStorageRepository) + { + _ninjaMappingService = ninjaMappingService ?? throw new ArgumentNullException(nameof(ninjaMappingService)); + _ninjaEntityTableStorageRepository = ninjaEntityTableStorageRepository ?? throw new ArgumentNullException(nameof(ninjaEntityTableStorageRepository)); + } + + public async Task CreateAsync(Ninja ninja) + { + var entityToCreate = _ninjaMappingService.Map(ninja); + var createdEntity = await _ninjaEntityTableStorageRepository.InsertOrReplaceAsync(entityToCreate); + var createNinja = _ninjaMappingService.Map(createdEntity); + return createNinja; + } + + public async Task DeleteAsync(string clanName, string ninjaKey) + { + var deletedEntity = await _ninjaEntityTableStorageRepository.RemoveAsync(clanName, ninjaKey); + var deletedNinja = _ninjaMappingService.Map(deletedEntity); + return deletedNinja; + } + + public async Task> ReadAllAsync() + { + var entities = await _ninjaEntityTableStorageRepository.ReadAllAsync(); + var ninja = _ninjaMappingService.Map(entities); + return ninja; + } + + public async Task> ReadAllInClanAsync(string clanName) + { + var entities = await _ninjaEntityTableStorageRepository.ReadPartitionAsync(clanName); + var ninja = _ninjaMappingService.Map(entities); + return ninja; + } + + public async Task ReadOneAsync(string clanName, string ninjaKey) + { + var entity = await _ninjaEntityTableStorageRepository.ReadOneAsync(clanName, ninjaKey); + var ninja = _ninjaMappingService.Map(entity); + return ninja; + } + + public async Task UpdateAsync(Ninja ninja) + { + var entityToUpdate = _ninjaMappingService.Map(ninja); + var updatedEntity = await _ninjaEntityTableStorageRepository.InsertOrMergeAsync(entityToUpdate); + var updatedNinja = _ninjaMappingService.Map(updatedEntity); + return updatedNinja; + } + } +} diff --git a/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/NinjaRepositoryTest.cs b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/NinjaRepositoryTest.cs new file mode 100644 index 0000000..470b2f7 --- /dev/null +++ b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/NinjaRepositoryTest.cs @@ -0,0 +1,222 @@ +using ForEvolve.Azure.Storage.Table; +using ForEvolve.Blog.Samples.NinjaApi.Models; +using ForEvolve.Blog.Samples.NinjaApi.Services; +using Moq; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Repositories +{ + public class NinjaRepositoryTest + { + protected NinjaRepository RepositoryUnderTest { get; } + + protected Mock NinjaMappingServiceMock { get; } + protected Mock> NinjaEntityTableStorageRepositoryMock { get; } + + public NinjaRepositoryTest() + { + NinjaMappingServiceMock = new Mock(); + NinjaEntityTableStorageRepositoryMock = new Mock>(); + RepositoryUnderTest = new NinjaRepository( + NinjaMappingServiceMock.Object, + NinjaEntityTableStorageRepositoryMock.Object + ); + } + + public class ReadAllAsync : NinjaRepositoryTest + { + [Fact] + public async Task Should_map_ReadAll_and_return_the_expected_ninja() + { + // Arrange + var entities = new NinjaEntity[0]; + var expectedNinja = new Ninja[0]; + + NinjaEntityTableStorageRepositoryMock + .Setup(x => x.ReadAllAsync()) + .ReturnsAsync(entities) + .Verifiable(); + NinjaMappingServiceMock + .Setup(x => x.Map(entities)) + .Returns(expectedNinja) + .Verifiable(); + + // Act + var result = await RepositoryUnderTest.ReadAllAsync(); + + // Assert + NinjaMappingServiceMock + .Verify(x => x.Map(entities), Times.Once); + NinjaEntityTableStorageRepositoryMock + .Verify(x => x.ReadAllAsync(), Times.Once); + Assert.Same(expectedNinja, result); + } + } + + public class ReadAllInClanAsync : NinjaRepositoryTest + { + [Fact] + public async Task Should_map_ReadPartition_and_return_the_expected_ninja() + { + // Arrange + var clanName = "My clan"; + var entities = new NinjaEntity[0]; + var expectedNinja = new Ninja[0]; + NinjaEntityTableStorageRepositoryMock + .Setup(x => x.ReadPartitionAsync(clanName)) + .ReturnsAsync(entities) + .Verifiable(); + NinjaMappingServiceMock + .Setup(x => x.Map(entities)) + .Returns(expectedNinja) + .Verifiable(); + + // Act + var result = await RepositoryUnderTest.ReadAllInClanAsync(clanName); + + // Assert + NinjaMappingServiceMock + .Verify(x => x.Map(entities), Times.Once); + NinjaEntityTableStorageRepositoryMock + .Verify(x => x.ReadPartitionAsync(clanName), Times.Once); + Assert.Same(expectedNinja, result); + } + } + + public class ReadOneAsync : NinjaRepositoryTest + { + [Fact] + public async Task Should_map_ReadOne_and_return_the_expected_ninja() + { + // Arrange + var clanName = "My clan"; + var ninjaKey = "123FB950-57DB-4CD0-B4D1-7E6B00A6163A"; + var entity = new NinjaEntity(); + var expectedNinja = new Ninja(); + + NinjaEntityTableStorageRepositoryMock + .Setup(x => x.ReadOneAsync(clanName, ninjaKey)) + .ReturnsAsync(entity) + .Verifiable(); + NinjaMappingServiceMock + .Setup(x => x.Map(entity)) + .Returns(expectedNinja) + .Verifiable(); + + // Act + var result = await RepositoryUnderTest.ReadOneAsync(clanName, ninjaKey); + + // Assert + NinjaMappingServiceMock + .Verify(x => x.Map(entity), Times.Once); + NinjaEntityTableStorageRepositoryMock + .Verify(x => x.ReadOneAsync(clanName, ninjaKey), Times.Once); + Assert.Same(expectedNinja, result); + } + } + + public class CreateAsync : NinjaRepositoryTest + { + [Fact] + public async Task Should_map_InsertOrReplace_and_return_the_expected_ninja() + { + // Arrange + var ninjaToCreate = new Ninja(); + var entityToCreate = new NinjaEntity(); + var createdEntity = new NinjaEntity(); + var expectedNinja = new Ninja(); + + NinjaMappingServiceMock + .Setup(x => x.Map(ninjaToCreate)) + .Returns(entityToCreate) + .Verifiable(); + NinjaEntityTableStorageRepositoryMock + .Setup(x => x.InsertOrReplaceAsync(entityToCreate)) + .ReturnsAsync(createdEntity) + .Verifiable(); + NinjaMappingServiceMock + .Setup(x => x.Map(createdEntity)) + .Returns(expectedNinja) + .Verifiable(); + + // Act + var result = await RepositoryUnderTest.CreateAsync(ninjaToCreate); + + // Assert + NinjaMappingServiceMock.Verify(x => x.Map(ninjaToCreate), Times.Once); + NinjaEntityTableStorageRepositoryMock.Verify(x => x.InsertOrReplaceAsync(entityToCreate), Times.Once); + NinjaMappingServiceMock.Verify(x => x.Map(createdEntity), Times.Once); + Assert.Same(expectedNinja, result); + } + } + + public class UpdateAsync : NinjaRepositoryTest + { + [Fact] + public async Task Should_map_InsertOrMerge_and_return_the_expected_ninja() + { + // Arrange + var ninjaToUpdate = new Ninja(); + var entityToUpdate = new NinjaEntity(); + var updatedEntity = new NinjaEntity(); + var expectedNinja = new Ninja(); + + NinjaMappingServiceMock + .Setup(x => x.Map(ninjaToUpdate)) + .Returns(entityToUpdate) + .Verifiable(); + NinjaEntityTableStorageRepositoryMock + .Setup(x => x.InsertOrMergeAsync(entityToUpdate)) + .ReturnsAsync(updatedEntity) + .Verifiable(); + NinjaMappingServiceMock + .Setup(x => x.Map(updatedEntity)) + .Returns(expectedNinja) + .Verifiable(); + + // Act + var result = await RepositoryUnderTest.UpdateAsync(ninjaToUpdate); + + // Assert + NinjaMappingServiceMock.Verify(x => x.Map(ninjaToUpdate), Times.Once); + NinjaEntityTableStorageRepositoryMock.Verify(x => x.InsertOrMergeAsync(entityToUpdate), Times.Once); + NinjaMappingServiceMock.Verify(x => x.Map(updatedEntity), Times.Once); + Assert.Same(expectedNinja, result); + } + } + + public class DeleteAsync : NinjaRepositoryTest + { + [Fact] + public async Task Should_map_Remove_and_return_the_expected_ninja() + { + // Arrange + var clanName = "My clan"; + var ninjaKey = "123FB950-57DB-4CD0-B4D1-7E6B00A6163A"; + var deletedEntity = new NinjaEntity(); + var expectedNinja = new Ninja(); + + NinjaEntityTableStorageRepositoryMock + .Setup(x => x.RemoveAsync(clanName, ninjaKey)) + .ReturnsAsync(deletedEntity) + .Verifiable(); + NinjaMappingServiceMock + .Setup(x => x.Map(deletedEntity)) + .Returns(expectedNinja) + .Verifiable(); + + // Act + var result = await RepositoryUnderTest.DeleteAsync(clanName, ninjaKey); + + // Assert + NinjaEntityTableStorageRepositoryMock.Verify(x => x.RemoveAsync(clanName, ninjaKey), Times.Once); + NinjaMappingServiceMock.Verify(x => x.Map(deletedEntity), Times.Once); + Assert.Same(expectedNinja, result); + } + } + } +} From 902e87710fb815ba5e1a266b09a323abf98686ed Mon Sep 17 00:00:00 2001 From: Carl-Hugo Marcotte Date: Fri, 25 Aug 2017 12:11:22 -0400 Subject: [PATCH 03/11] Refactored NinjaEntityEnumerableToNinjaMapper to EnumerableMapper --- .../Mappers/EnumerableMapper.cs | 30 +++++++++++++++++++ .../NinjaEntityEnumerableToNinjaMapper.cs | 30 ------------------- .../NinjaEntityEnumerableToNinjaMapperTest.cs | 4 +-- 3 files changed, 32 insertions(+), 32 deletions(-) create mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/EnumerableMapper.cs delete mode 100644 9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/EnumerableMapper.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/EnumerableMapper.cs new file mode 100644 index 0000000..be141da --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/EnumerableMapper.cs @@ -0,0 +1,30 @@ +using ForEvolve.Blog.Samples.NinjaApi.Mappers; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public class EnumerableMapper : IMapper, IEnumerable> + { + private readonly IMapper _singleMapper; + + public EnumerableMapper(IMapper singleMapper) + { + _singleMapper = singleMapper ?? throw new ArgumentNullException(nameof(singleMapper)); + } + + public IEnumerable Map(IEnumerable source) + { + var count = source.Count(); + var destination = new TDestination[count]; + for (int i = 0; i < count; i++) + { + var currentSource = source.ElementAt(i); + var currentDestination = _singleMapper.Map(currentSource); + destination[i] = currentDestination; + } + return destination; + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs deleted file mode 100644 index 138aac7..0000000 --- a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs +++ /dev/null @@ -1,30 +0,0 @@ -using ForEvolve.Blog.Samples.NinjaApi.Models; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace ForEvolve.Blog.Samples.NinjaApi.Mappers -{ - public class NinjaEntityEnumerableToNinjaMapper : IMapper, IEnumerable> - { - private readonly IMapper _ninjaEntityToNinjaMapper; - - public NinjaEntityEnumerableToNinjaMapper(IMapper ninjaEntityToNinjaMapper) - { - _ninjaEntityToNinjaMapper = ninjaEntityToNinjaMapper ?? throw new ArgumentNullException(nameof(ninjaEntityToNinjaMapper)); - } - - public IEnumerable Map(IEnumerable entities) - { - var count = entities.Count(); - var all = new Ninja[count]; - for (int i = 0; i < count; i++) - { - var entity = entities.ElementAt(i); - var ninja = _ninjaEntityToNinjaMapper.Map(entity); - all[i] = ninja; - } - return all; - } - } -} diff --git a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs index 145e2a7..6f9d532 100644 --- a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs +++ b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs @@ -9,13 +9,13 @@ namespace ForEvolve.Blog.Samples.NinjaApi.Mappers { public class NinjaEntityEnumerableToNinjaMapperTest { - protected NinjaEntityEnumerableToNinjaMapper MapperUnderTest { get; } + protected EnumerableMapper MapperUnderTest { get; } protected Mock> NinjaEntityToNinjaMapperMock { get; } public NinjaEntityEnumerableToNinjaMapperTest() { NinjaEntityToNinjaMapperMock = new Mock>(); - MapperUnderTest = new NinjaEntityEnumerableToNinjaMapper(NinjaEntityToNinjaMapperMock.Object); + MapperUnderTest = new EnumerableMapper(NinjaEntityToNinjaMapperMock.Object); } public class Map : NinjaEntityEnumerableToNinjaMapperTest From 2f2f1a7571a329a541e4ca30e320eea35cdc7296 Mon Sep 17 00:00:00 2001 From: Carl-Hugo Marcotte Date: Fri, 25 Aug 2017 12:38:11 -0400 Subject: [PATCH 04/11] Refactored NinjaEntityEnumerableToNinjaMapperTest to EnumerableMapperTest --- .../Mappers/EnumerableMapperTest.cs | 48 +++++++++++++++++++ .../NinjaEntityEnumerableToNinjaMapperTest.cs | 45 ----------------- 2 files changed, 48 insertions(+), 45 deletions(-) create mode 100644 9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/EnumerableMapperTest.cs delete mode 100644 9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs diff --git a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/EnumerableMapperTest.cs b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/EnumerableMapperTest.cs new file mode 100644 index 0000000..6aafbb8 --- /dev/null +++ b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/EnumerableMapperTest.cs @@ -0,0 +1,48 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using Moq; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public class EnumerableMapperTest + { + public class Map : EnumerableMapperTest + { + public class NinjaEntity2Ninja : Map + { + protected EnumerableMapper MapperUnderTest { get; } + protected Mock> NinjaEntityToNinjaMapperMock { get; } + + public NinjaEntity2Ninja() + { + NinjaEntityToNinjaMapperMock = new Mock>(); + MapperUnderTest = new EnumerableMapper(NinjaEntityToNinjaMapperMock.Object); + } + + [Fact] + public void Should_delegate_mapping_to_the_sinlge_entity_mapper() + { + // Arrange + var ninja1 = new NinjaEntity(); + var ninja2 = new NinjaEntity(); + var ninjaEntities = new List { ninja1, ninja2 }; + + NinjaEntityToNinjaMapperMock + .Setup(x => x.Map(It.IsAny())) + .Returns(new Ninja()) + .Verifiable(); + + // Act + var result = MapperUnderTest.Map(ninjaEntities); + + // Assert + NinjaEntityToNinjaMapperMock.Verify(x => x.Map(ninja1), Times.Once); + NinjaEntityToNinjaMapperMock.Verify(x => x.Map(ninja2), Times.Once); + } + } + } + } +} diff --git a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs deleted file mode 100644 index 6f9d532..0000000 --- a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs +++ /dev/null @@ -1,45 +0,0 @@ -using ForEvolve.Blog.Samples.NinjaApi.Models; -using Moq; -using System; -using System.Collections.Generic; -using System.Text; -using Xunit; - -namespace ForEvolve.Blog.Samples.NinjaApi.Mappers -{ - public class NinjaEntityEnumerableToNinjaMapperTest - { - protected EnumerableMapper MapperUnderTest { get; } - protected Mock> NinjaEntityToNinjaMapperMock { get; } - - public NinjaEntityEnumerableToNinjaMapperTest() - { - NinjaEntityToNinjaMapperMock = new Mock>(); - MapperUnderTest = new EnumerableMapper(NinjaEntityToNinjaMapperMock.Object); - } - - public class Map : NinjaEntityEnumerableToNinjaMapperTest - { - [Fact] - public void Should_delegate_mapping_to_the_sinlge_entity_mapper() - { - // Arrange - var ninja1 = new NinjaEntity(); - var ninja2 = new NinjaEntity(); - var ninjaEntities = new List { ninja1, ninja2 }; - - NinjaEntityToNinjaMapperMock - .Setup(x => x.Map(It.IsAny())) - .Returns(new Ninja()) - .Verifiable(); - - // Act - var result = MapperUnderTest.Map(ninjaEntities); - - // Assert - NinjaEntityToNinjaMapperMock.Verify(x => x.Map(ninja1), Times.Once); - NinjaEntityToNinjaMapperMock.Verify(x => x.Map(ninja2), Times.Once); - } - } - } -} From 0c5f863708d6d70006c87b1d202dd50ae564d187 Mon Sep 17 00:00:00 2001 From: Carl-Hugo Marcotte Date: Fri, 25 Aug 2017 12:40:55 -0400 Subject: [PATCH 05/11] typo --- .../Mappers/EnumerableMapperTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/EnumerableMapperTest.cs b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/EnumerableMapperTest.cs index 6aafbb8..ec08439 100644 --- a/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/EnumerableMapperTest.cs +++ b/9. NinjaApi - NinjaMappingService/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/EnumerableMapperTest.cs @@ -23,7 +23,7 @@ public NinjaEntity2Ninja() } [Fact] - public void Should_delegate_mapping_to_the_sinlge_entity_mapper() + public void Should_delegate_mapping_to_the_single_entity_mapper() { // Arrange var ninja1 = new NinjaEntity(); From f419c6d9d63d7976e7924c1db80dcbe172d0b293 Mon Sep 17 00:00:00 2001 From: Carl-Hugo Marcotte Date: Fri, 25 Aug 2017 12:58:56 -0400 Subject: [PATCH 06/11] Migrated part 9 refactoring to part 10 & 11 --- .../Mappers/EnumerableMapper.cs | 30 ++++++++++++ .../NinjaEntityEnumerableToNinjaMapper.cs | 30 ------------ .../Mappers/EnumerableMapperTest.cs | 48 +++++++++++++++++++ .../NinjaEntityEnumerableToNinjaMapperTest.cs | 45 ----------------- .../Mappers/EnumerableMapper.cs | 30 ++++++++++++ .../NinjaEntityEnumerableToNinjaMapper.cs | 30 ------------ .../Mappers/EnumerableMapperTest.cs | 48 +++++++++++++++++++ .../NinjaEntityEnumerableToNinjaMapperTest.cs | 45 ----------------- 8 files changed, 156 insertions(+), 150 deletions(-) create mode 100644 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/EnumerableMapper.cs delete mode 100644 10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs create mode 100644 10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/EnumerableMapperTest.cs delete mode 100644 10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs create mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/EnumerableMapper.cs delete mode 100644 11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs create mode 100644 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/EnumerableMapperTest.cs delete mode 100644 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs diff --git a/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/EnumerableMapper.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/EnumerableMapper.cs new file mode 100644 index 0000000..be141da --- /dev/null +++ b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/EnumerableMapper.cs @@ -0,0 +1,30 @@ +using ForEvolve.Blog.Samples.NinjaApi.Mappers; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public class EnumerableMapper : IMapper, IEnumerable> + { + private readonly IMapper _singleMapper; + + public EnumerableMapper(IMapper singleMapper) + { + _singleMapper = singleMapper ?? throw new ArgumentNullException(nameof(singleMapper)); + } + + public IEnumerable Map(IEnumerable source) + { + var count = source.Count(); + var destination = new TDestination[count]; + for (int i = 0; i < count; i++) + { + var currentSource = source.ElementAt(i); + var currentDestination = _singleMapper.Map(currentSource); + destination[i] = currentDestination; + } + return destination; + } + } +} diff --git a/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs deleted file mode 100644 index 138aac7..0000000 --- a/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs +++ /dev/null @@ -1,30 +0,0 @@ -using ForEvolve.Blog.Samples.NinjaApi.Models; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace ForEvolve.Blog.Samples.NinjaApi.Mappers -{ - public class NinjaEntityEnumerableToNinjaMapper : IMapper, IEnumerable> - { - private readonly IMapper _ninjaEntityToNinjaMapper; - - public NinjaEntityEnumerableToNinjaMapper(IMapper ninjaEntityToNinjaMapper) - { - _ninjaEntityToNinjaMapper = ninjaEntityToNinjaMapper ?? throw new ArgumentNullException(nameof(ninjaEntityToNinjaMapper)); - } - - public IEnumerable Map(IEnumerable entities) - { - var count = entities.Count(); - var all = new Ninja[count]; - for (int i = 0; i < count; i++) - { - var entity = entities.ElementAt(i); - var ninja = _ninjaEntityToNinjaMapper.Map(entity); - all[i] = ninja; - } - return all; - } - } -} diff --git a/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/EnumerableMapperTest.cs b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/EnumerableMapperTest.cs new file mode 100644 index 0000000..ec08439 --- /dev/null +++ b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/EnumerableMapperTest.cs @@ -0,0 +1,48 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using Moq; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public class EnumerableMapperTest + { + public class Map : EnumerableMapperTest + { + public class NinjaEntity2Ninja : Map + { + protected EnumerableMapper MapperUnderTest { get; } + protected Mock> NinjaEntityToNinjaMapperMock { get; } + + public NinjaEntity2Ninja() + { + NinjaEntityToNinjaMapperMock = new Mock>(); + MapperUnderTest = new EnumerableMapper(NinjaEntityToNinjaMapperMock.Object); + } + + [Fact] + public void Should_delegate_mapping_to_the_single_entity_mapper() + { + // Arrange + var ninja1 = new NinjaEntity(); + var ninja2 = new NinjaEntity(); + var ninjaEntities = new List { ninja1, ninja2 }; + + NinjaEntityToNinjaMapperMock + .Setup(x => x.Map(It.IsAny())) + .Returns(new Ninja()) + .Verifiable(); + + // Act + var result = MapperUnderTest.Map(ninjaEntities); + + // Assert + NinjaEntityToNinjaMapperMock.Verify(x => x.Map(ninja1), Times.Once); + NinjaEntityToNinjaMapperMock.Verify(x => x.Map(ninja2), Times.Once); + } + } + } + } +} diff --git a/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs deleted file mode 100644 index 145e2a7..0000000 --- a/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs +++ /dev/null @@ -1,45 +0,0 @@ -using ForEvolve.Blog.Samples.NinjaApi.Models; -using Moq; -using System; -using System.Collections.Generic; -using System.Text; -using Xunit; - -namespace ForEvolve.Blog.Samples.NinjaApi.Mappers -{ - public class NinjaEntityEnumerableToNinjaMapperTest - { - protected NinjaEntityEnumerableToNinjaMapper MapperUnderTest { get; } - protected Mock> NinjaEntityToNinjaMapperMock { get; } - - public NinjaEntityEnumerableToNinjaMapperTest() - { - NinjaEntityToNinjaMapperMock = new Mock>(); - MapperUnderTest = new NinjaEntityEnumerableToNinjaMapper(NinjaEntityToNinjaMapperMock.Object); - } - - public class Map : NinjaEntityEnumerableToNinjaMapperTest - { - [Fact] - public void Should_delegate_mapping_to_the_sinlge_entity_mapper() - { - // Arrange - var ninja1 = new NinjaEntity(); - var ninja2 = new NinjaEntity(); - var ninjaEntities = new List { ninja1, ninja2 }; - - NinjaEntityToNinjaMapperMock - .Setup(x => x.Map(It.IsAny())) - .Returns(new Ninja()) - .Verifiable(); - - // Act - var result = MapperUnderTest.Map(ninjaEntities); - - // Assert - NinjaEntityToNinjaMapperMock.Verify(x => x.Map(ninja1), Times.Once); - NinjaEntityToNinjaMapperMock.Verify(x => x.Map(ninja2), Times.Once); - } - } - } -} diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/EnumerableMapper.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/EnumerableMapper.cs new file mode 100644 index 0000000..be141da --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/EnumerableMapper.cs @@ -0,0 +1,30 @@ +using ForEvolve.Blog.Samples.NinjaApi.Mappers; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public class EnumerableMapper : IMapper, IEnumerable> + { + private readonly IMapper _singleMapper; + + public EnumerableMapper(IMapper singleMapper) + { + _singleMapper = singleMapper ?? throw new ArgumentNullException(nameof(singleMapper)); + } + + public IEnumerable Map(IEnumerable source) + { + var count = source.Count(); + var destination = new TDestination[count]; + for (int i = 0; i < count; i++) + { + var currentSource = source.ElementAt(i); + var currentDestination = _singleMapper.Map(currentSource); + destination[i] = currentDestination; + } + return destination; + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs deleted file mode 100644 index 138aac7..0000000 --- a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Mappers/NinjaEntityEnumerableToNinjaMapper.cs +++ /dev/null @@ -1,30 +0,0 @@ -using ForEvolve.Blog.Samples.NinjaApi.Models; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace ForEvolve.Blog.Samples.NinjaApi.Mappers -{ - public class NinjaEntityEnumerableToNinjaMapper : IMapper, IEnumerable> - { - private readonly IMapper _ninjaEntityToNinjaMapper; - - public NinjaEntityEnumerableToNinjaMapper(IMapper ninjaEntityToNinjaMapper) - { - _ninjaEntityToNinjaMapper = ninjaEntityToNinjaMapper ?? throw new ArgumentNullException(nameof(ninjaEntityToNinjaMapper)); - } - - public IEnumerable Map(IEnumerable entities) - { - var count = entities.Count(); - var all = new Ninja[count]; - for (int i = 0; i < count; i++) - { - var entity = entities.ElementAt(i); - var ninja = _ninjaEntityToNinjaMapper.Map(entity); - all[i] = ninja; - } - return all; - } - } -} diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/EnumerableMapperTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/EnumerableMapperTest.cs new file mode 100644 index 0000000..ec08439 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/EnumerableMapperTest.cs @@ -0,0 +1,48 @@ +using ForEvolve.Blog.Samples.NinjaApi.Models; +using Moq; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace ForEvolve.Blog.Samples.NinjaApi.Mappers +{ + public class EnumerableMapperTest + { + public class Map : EnumerableMapperTest + { + public class NinjaEntity2Ninja : Map + { + protected EnumerableMapper MapperUnderTest { get; } + protected Mock> NinjaEntityToNinjaMapperMock { get; } + + public NinjaEntity2Ninja() + { + NinjaEntityToNinjaMapperMock = new Mock>(); + MapperUnderTest = new EnumerableMapper(NinjaEntityToNinjaMapperMock.Object); + } + + [Fact] + public void Should_delegate_mapping_to_the_single_entity_mapper() + { + // Arrange + var ninja1 = new NinjaEntity(); + var ninja2 = new NinjaEntity(); + var ninjaEntities = new List { ninja1, ninja2 }; + + NinjaEntityToNinjaMapperMock + .Setup(x => x.Map(It.IsAny())) + .Returns(new Ninja()) + .Verifiable(); + + // Act + var result = MapperUnderTest.Map(ninjaEntities); + + // Assert + NinjaEntityToNinjaMapperMock.Verify(x => x.Map(ninja1), Times.Once); + NinjaEntityToNinjaMapperMock.Verify(x => x.Map(ninja2), Times.Once); + } + } + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs deleted file mode 100644 index 145e2a7..0000000 --- a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Mappers/NinjaEntityEnumerableToNinjaMapperTest.cs +++ /dev/null @@ -1,45 +0,0 @@ -using ForEvolve.Blog.Samples.NinjaApi.Models; -using Moq; -using System; -using System.Collections.Generic; -using System.Text; -using Xunit; - -namespace ForEvolve.Blog.Samples.NinjaApi.Mappers -{ - public class NinjaEntityEnumerableToNinjaMapperTest - { - protected NinjaEntityEnumerableToNinjaMapper MapperUnderTest { get; } - protected Mock> NinjaEntityToNinjaMapperMock { get; } - - public NinjaEntityEnumerableToNinjaMapperTest() - { - NinjaEntityToNinjaMapperMock = new Mock>(); - MapperUnderTest = new NinjaEntityEnumerableToNinjaMapper(NinjaEntityToNinjaMapperMock.Object); - } - - public class Map : NinjaEntityEnumerableToNinjaMapperTest - { - [Fact] - public void Should_delegate_mapping_to_the_sinlge_entity_mapper() - { - // Arrange - var ninja1 = new NinjaEntity(); - var ninja2 = new NinjaEntity(); - var ninjaEntities = new List { ninja1, ninja2 }; - - NinjaEntityToNinjaMapperMock - .Setup(x => x.Map(It.IsAny())) - .Returns(new Ninja()) - .Verifiable(); - - // Act - var result = MapperUnderTest.Map(ninjaEntities); - - // Assert - NinjaEntityToNinjaMapperMock.Verify(x => x.Map(ninja1), Times.Once); - NinjaEntityToNinjaMapperMock.Verify(x => x.Map(ninja2), Times.Once); - } - } - } -} From f1fcddf0bd249d9d564c879840269a4adaf88d38 Mon Sep 17 00:00:00 2001 From: Carl-Hugo Marcotte Date: Fri, 25 Aug 2017 16:15:42 -0400 Subject: [PATCH 07/11] Updated ForEvolve to version 1.0.0-upsilon-180 --- .../ForEvolve.Blog.Samples.NinjaApi.csproj | 2 +- .../ForEvolve.Blog.Samples.NinjaApi.csproj | 2 +- .../ForEvolve.Blog.Samples.NinjaApi.csproj | 2 +- .../ForEvolve.Blog.Samples.NinjaApi.csproj | 2 +- .../ForEvolve.Blog.Samples.NinjaApi.csproj | 2 +- .../ForEvolve.Blog.Samples.NinjaApi.csproj | 2 +- .../ForEvolve.Blog.Samples.NinjaApi.csproj | 2 +- .../ForEvolve.Blog.Samples.NinjaApi.csproj | 2 +- .../ForEvolve.Blog.Samples.NinjaApi.csproj | 2 +- .../ForEvolve.Blog.Samples.NinjaApi.csproj | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/1. NinjaApi - Starting point/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj b/1. NinjaApi - Starting point/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj index 826c251..8cb226a 100644 --- a/1. NinjaApi - Starting point/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj +++ b/1. NinjaApi - Starting point/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj @@ -6,7 +6,7 @@ - + diff --git a/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj index 4c0cd14..2272ce1 100644 --- a/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj +++ b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj @@ -7,7 +7,7 @@ - + diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj index 4c0cd14..2272ce1 100644 --- a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj @@ -7,7 +7,7 @@ - + diff --git a/3. NinjaApi - ClansControllers/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj b/3. NinjaApi - ClansControllers/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj index 826c251..8cb226a 100644 --- a/3. NinjaApi - ClansControllers/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj +++ b/3. NinjaApi - ClansControllers/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj @@ -6,7 +6,7 @@ - + diff --git a/4. NinjaApi - The ClanService/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj b/4. NinjaApi - The ClanService/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj index 4c0cd14..2272ce1 100644 --- a/4. NinjaApi - The ClanService/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj +++ b/4. NinjaApi - The ClanService/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj @@ -7,7 +7,7 @@ - + diff --git a/5. NinjaApi - Clans completed/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj b/5. NinjaApi - Clans completed/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj index 4c0cd14..2272ce1 100644 --- a/5. NinjaApi - Clans completed/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj +++ b/5. NinjaApi - Clans completed/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj @@ -7,7 +7,7 @@ - + diff --git a/6. NinjaApi - NinjaController/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj b/6. NinjaApi - NinjaController/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj index 4c0cd14..2272ce1 100644 --- a/6. NinjaApi - NinjaController/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj +++ b/6. NinjaApi - NinjaController/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj @@ -7,7 +7,7 @@ - + diff --git a/7. NinjaApi - NinjaService/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj b/7. NinjaApi - NinjaService/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj index 4c0cd14..2272ce1 100644 --- a/7. NinjaApi - NinjaService/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj +++ b/7. NinjaApi - NinjaService/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj @@ -7,7 +7,7 @@ - + diff --git a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj index 4c0cd14..2272ce1 100644 --- a/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj +++ b/8. NinjaApi - NinjaEntity/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj @@ -7,7 +7,7 @@ - + diff --git a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj index 4c0cd14..2272ce1 100644 --- a/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj +++ b/9. NinjaApi - NinjaMappingService/src/ForEvolve.Blog.Samples.NinjaApi/ForEvolve.Blog.Samples.NinjaApi.csproj @@ -7,7 +7,7 @@ - + From 596efab44d1e0152d5131def4666c3a100e1f561 Mon Sep 17 00:00:00 2001 From: Carl-Hugo Marcotte Date: Fri, 25 Aug 2017 16:19:05 -0400 Subject: [PATCH 08/11] Updated NinjaRepository to support ForEvolve-180 --- .../Repositories/NinjaRepository.cs | 2 +- .../Repositories/NinjaRepositoryTest.cs | 4 ++-- .../Repositories/NinjaRepository.cs | 2 +- .../Repositories/NinjaRepositoryTest.cs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/NinjaRepository.cs b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/NinjaRepository.cs index 01e5210..747e861 100644 --- a/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/NinjaRepository.cs +++ b/10. NinjaApi - NinjaRepository/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/NinjaRepository.cs @@ -29,7 +29,7 @@ public async Task CreateAsync(Ninja ninja) public async Task DeleteAsync(string clanName, string ninjaKey) { - var deletedEntity = await _ninjaEntityTableStorageRepository.RemoveAsync(clanName, ninjaKey); + var deletedEntity = await _ninjaEntityTableStorageRepository.DeleteOneAsync(clanName, ninjaKey); var deletedNinja = _ninjaMappingService.Map(deletedEntity); return deletedNinja; } diff --git a/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/NinjaRepositoryTest.cs b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/NinjaRepositoryTest.cs index 470b2f7..5b91745 100644 --- a/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/NinjaRepositoryTest.cs +++ b/10. NinjaApi - NinjaRepository/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/NinjaRepositoryTest.cs @@ -201,7 +201,7 @@ public async Task Should_map_Remove_and_return_the_expected_ninja() var expectedNinja = new Ninja(); NinjaEntityTableStorageRepositoryMock - .Setup(x => x.RemoveAsync(clanName, ninjaKey)) + .Setup(x => x.DeleteOneAsync(clanName, ninjaKey)) .ReturnsAsync(deletedEntity) .Verifiable(); NinjaMappingServiceMock @@ -213,7 +213,7 @@ public async Task Should_map_Remove_and_return_the_expected_ninja() var result = await RepositoryUnderTest.DeleteAsync(clanName, ninjaKey); // Assert - NinjaEntityTableStorageRepositoryMock.Verify(x => x.RemoveAsync(clanName, ninjaKey), Times.Once); + NinjaEntityTableStorageRepositoryMock.Verify(x => x.DeleteOneAsync(clanName, ninjaKey), Times.Once); NinjaMappingServiceMock.Verify(x => x.Map(deletedEntity), Times.Once); Assert.Same(expectedNinja, result); } diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/NinjaRepository.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/NinjaRepository.cs index 01e5210..747e861 100644 --- a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/NinjaRepository.cs +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Repositories/NinjaRepository.cs @@ -29,7 +29,7 @@ public async Task CreateAsync(Ninja ninja) public async Task DeleteAsync(string clanName, string ninjaKey) { - var deletedEntity = await _ninjaEntityTableStorageRepository.RemoveAsync(clanName, ninjaKey); + var deletedEntity = await _ninjaEntityTableStorageRepository.DeleteOneAsync(clanName, ninjaKey); var deletedNinja = _ninjaMappingService.Map(deletedEntity); return deletedNinja; } diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/NinjaRepositoryTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/NinjaRepositoryTest.cs index 470b2f7..5b91745 100644 --- a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/NinjaRepositoryTest.cs +++ b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.Tests/Repositories/NinjaRepositoryTest.cs @@ -201,7 +201,7 @@ public async Task Should_map_Remove_and_return_the_expected_ninja() var expectedNinja = new Ninja(); NinjaEntityTableStorageRepositoryMock - .Setup(x => x.RemoveAsync(clanName, ninjaKey)) + .Setup(x => x.DeleteOneAsync(clanName, ninjaKey)) .ReturnsAsync(deletedEntity) .Verifiable(); NinjaMappingServiceMock @@ -213,7 +213,7 @@ public async Task Should_map_Remove_and_return_the_expected_ninja() var result = await RepositoryUnderTest.DeleteAsync(clanName, ninjaKey); // Assert - NinjaEntityTableStorageRepositoryMock.Verify(x => x.RemoveAsync(clanName, ninjaKey), Times.Once); + NinjaEntityTableStorageRepositoryMock.Verify(x => x.DeleteOneAsync(clanName, ninjaKey), Times.Once); NinjaMappingServiceMock.Verify(x => x.Map(deletedEntity), Times.Once); Assert.Same(expectedNinja, result); } From 2e56ac16724412f25e665c6eff0836e640e76249 Mon Sep 17 00:00:00 2001 From: Carl-Hugo Marcotte Date: Thu, 31 Aug 2017 12:50:50 -0400 Subject: [PATCH 09/11] Updated IntegrationTests.NinjaControllerTest - Replaced NinjaEntityTableStorageRepositoryFake by a Mock --- .../Startup.cs | 2 +- ...g.Samples.NinjaApi.IntegrationTests.csproj | 1 + .../NinjaControllerTest.cs | 121 ++++++++++++------ .../NinjaEntityTableStorageRepositoryFake.cs | 97 -------------- .../StartupTest.cs | 13 ++ 5 files changed, 100 insertions(+), 134 deletions(-) delete mode 100644 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaEntityTableStorageRepositoryFake.cs diff --git a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs index 51d9a56..9ce0cc9 100644 --- a/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs +++ b/11. NinjaApi - IntegrationTesting/src/ForEvolve.Blog.Samples.NinjaApi/Startup.cs @@ -40,7 +40,7 @@ public void ConfigureServices(IServiceCollection services) // Mappers services.TryAddSingleton, NinjaToNinjaEntityMapper>(); services.TryAddSingleton, NinjaEntityToNinjaMapper>(); - services.TryAddSingleton, IEnumerable>, NinjaEntityEnumerableToNinjaMapper>(); + services.TryAddSingleton, IEnumerable>, EnumerableMapper>(); // Ninja services.TryAddSingleton(); diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj index 1ecce38..13ba14c 100644 --- a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj +++ b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests.csproj @@ -17,6 +17,7 @@ + diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaControllerTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaControllerTest.cs index edcceb9..08ff905 100644 --- a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaControllerTest.cs +++ b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaControllerTest.cs @@ -7,28 +7,30 @@ using ForEvolve.Blog.Samples.NinjaApi.Models; using System.Collections.Generic; using System.Threading.Tasks; +using Moq; namespace ForEvolve.Blog.Samples.NinjaApi.IntegrationTests { public class NinjaControllerTest : BaseHttpTest { - protected NinjaEntityTableStorageRepositoryFake TableStorageFake { get; } + protected Mock> TableStorageMock { get; } protected string ClanName1 => "Iga"; protected string ClanName2 => "Kōga"; public NinjaControllerTest() { - TableStorageFake = new NinjaEntityTableStorageRepositoryFake(); + TableStorageMock = new Mock>(); } protected override void ConfigureServices(IServiceCollection services) { - services.AddSingleton>(x => TableStorageFake); - services.AddSingleton>(x => new List { - new Clan{ Name = ClanName1 }, - new Clan{ Name = ClanName2 } - }); + services + .AddSingleton(x => TableStorageMock.Object) + .AddSingleton>(x => new List { + new Clan{ Name = ClanName1 }, + new Clan{ Name = ClanName2 } + }); } public class ReadAllAsync : NinjaControllerTest @@ -37,10 +39,15 @@ public class ReadAllAsync : NinjaControllerTest public async Task Should_return_all_ninja_in_azure_table() { // Arrange - var superClanNinja = PopulateTableStorageFake(amountOfNinjaToCreate: 2, clanName: ClanName1); - var otherClanNinja = PopulateTableStorageFake(amountOfNinjaToCreate: 2, clanName: ClanName2); + var superClanNinja = CreateEntities(amountOfNinjaToCreate: 2, clanName: ClanName1); + var otherClanNinja = CreateEntities(amountOfNinjaToCreate: 2, clanName: ClanName2); + var all = superClanNinja.Union(otherClanNinja).ToArray(); var expectedNinjaLength = 4; + TableStorageMock + .Setup(x => x.ReadAllAsync()) + .ReturnsAsync(all); + // Act var result = await Client.GetAsync("v1/ninja"); @@ -50,10 +57,10 @@ public async Task Should_return_all_ninja_in_azure_table() Assert.NotNull(ninja); Assert.Equal(expectedNinjaLength, ninja.Length); Assert.Collection(ninja, - n => AssertNinjaEntityEqualNinja(superClanNinja[0], n), - n => AssertNinjaEntityEqualNinja(superClanNinja[1], n), - n => AssertNinjaEntityEqualNinja(otherClanNinja[0], n), - n => AssertNinjaEntityEqualNinja(otherClanNinja[1], n) + n => AssertNinjaEntityEqualNinja(all[0], n), + n => AssertNinjaEntityEqualNinja(all[1], n), + n => AssertNinjaEntityEqualNinja(all[2], n), + n => AssertNinjaEntityEqualNinja(all[3], n) ); } } @@ -65,11 +72,13 @@ public async Task Should_return_all_ninja_in_azure_table_partition() { // Arrange var expectedClanName = ClanName2; - var superClanNinja = PopulateTableStorageFake(amountOfNinjaToCreate: 2, clanName: ClanName1); - var otherClanNinja = PopulateTableStorageFake(amountOfNinjaToCreate: 2, clanName: expectedClanName); - var expectedNinja = superClanNinja.Concat(otherClanNinja); + var expectedNinja = CreateEntities(amountOfNinjaToCreate: 2, clanName: expectedClanName).ToArray(); var expectedNinjaLength = 2; + TableStorageMock + .Setup(x => x.ReadPartitionAsync(expectedClanName)) + .ReturnsAsync(expectedNinja); + // Act var result = await Client.GetAsync($"v1/ninja/{expectedClanName}"); @@ -79,8 +88,8 @@ public async Task Should_return_all_ninja_in_azure_table_partition() Assert.NotNull(ninja); Assert.Equal(expectedNinjaLength, ninja.Length); Assert.Collection(ninja, - n => AssertNinjaEntityEqualNinja(otherClanNinja[0], n), - n => AssertNinjaEntityEqualNinja(otherClanNinja[1], n) + n => AssertNinjaEntityEqualNinja(expectedNinja[0], n), + n => AssertNinjaEntityEqualNinja(expectedNinja[1], n) ); } } @@ -91,12 +100,14 @@ public class ReadOneAsync : NinjaControllerTest public async Task Should_return_one_ninja_from_azure_table() { // Arrange - var superClanNinja = PopulateTableStorageFake(amountOfNinjaToCreate: 5, clanName: ClanName1); - var otherClanNinja = PopulateTableStorageFake(amountOfNinjaToCreate: 5, clanName: ClanName2); - var expectedNinja = superClanNinja[3]; + var expectedNinja = CreateEntity(ClanName1); var clanName = expectedNinja.PartitionKey; var ninjaKey = expectedNinja.RowKey; + TableStorageMock + .Setup(x => x.ReadOneAsync(clanName, ninjaKey)) + .ReturnsAsync(expectedNinja); + // Act var result = await Client.GetAsync($"v1/ninja/{clanName}/{ninjaKey}"); @@ -123,6 +134,15 @@ public async Task Should_create_the_ninja_in_azure_table() }; var ninjaBody = ninjaToCreate.ToJsonHttpContent(); + var mapper = new Mappers.NinjaEntityToNinjaMapper(); + NinjaEntity createdEntity = null; + TableStorageMock + .Setup(x => x.InsertOrReplaceAsync(It.IsAny())) + .ReturnsAsync((NinjaEntity x) => { + createdEntity = x; + return x; + }); + // Act var result = await Client.PostAsync("v1/ninja", ninjaBody); @@ -130,8 +150,8 @@ public async Task Should_create_the_ninja_in_azure_table() result.EnsureSuccessStatusCode(); var ninja = await result.Content.ReadAsJsonObjectAsync(); Assert.NotNull(ninja); - Assert.Equal(1, TableStorageFake.EntityCount); - AssertNinjaEntityEqualNinja(TableStorageFake.ElementAt(0), ninja); + Assert.NotNull(createdEntity); + AssertNinjaEntityEqualNinja(createdEntity, ninja); } } @@ -141,16 +161,26 @@ public class UpdateAsync : NinjaControllerTest public async Task Should_update_the_ninja_in_azure_table() { // Arrange - var superClanNinja = PopulateTableStorageFake(amountOfNinjaToCreate: 1, clanName: ClanName1); var ninjaToUpdate = new Ninja { - Clan = new Clan { Name = superClanNinja[0].PartitionKey }, - Key = superClanNinja[0].RowKey, + Clan = new Clan { Name = ClanName1 }, + Key = "Some UpdateAsync Ninja Key", Name = "My new name", Level = 1234 }; var ninjaBody = ninjaToUpdate.ToJsonHttpContent(); + NinjaEntity updatedEntity = null; + TableStorageMock + .Setup(x => x.InsertOrMergeAsync(It.IsAny())) + .ReturnsAsync((NinjaEntity n) => + { + updatedEntity = n; + return n; + }); + TableStorageMock + .SetupEnforceNinjaExistenceAsync(ClanName1, ninjaToUpdate.Key); + // Act var result = await Client.PutAsync("v1/ninja", ninjaBody); @@ -158,8 +188,8 @@ public async Task Should_update_the_ninja_in_azure_table() result.EnsureSuccessStatusCode(); var ninja = await result.Content.ReadAsJsonObjectAsync(); Assert.NotNull(ninja); - Assert.Equal(1, TableStorageFake.EntityCount); - TableStorageFake.HasBeenMerged(superClanNinja[0]); + Assert.NotNull(updatedEntity); + AssertNinjaEntityEqualNinja(updatedEntity, ninja); } } @@ -169,11 +199,16 @@ public class DeleteAsync : NinjaControllerTest public async Task Should_delete_the_ninja_from_azure_table() { // Arrange - var superClanNinja = PopulateTableStorageFake(amountOfNinjaToCreate: 3, clanName: ClanName1); - var ninjaToDelete = superClanNinja[0]; + var ninjaToDelete = CreateEntity(ClanName1); var clanName = ninjaToDelete.PartitionKey; var ninjaKey = ninjaToDelete.RowKey; + TableStorageMock + .SetupEnforceNinjaExistenceAsync(clanName, ninjaKey); + TableStorageMock + .Setup(x => x.DeleteOneAsync(clanName, ninjaKey)) + .ReturnsAsync(ninjaToDelete); + // Act var result = await Client.DeleteAsync($"v1/ninja/{clanName}/{ninjaKey}"); @@ -181,14 +216,18 @@ public async Task Should_delete_the_ninja_from_azure_table() result.EnsureSuccessStatusCode(); var ninja = await result.Content.ReadAsJsonObjectAsync(); Assert.NotNull(ninja); - Assert.Equal(2, TableStorageFake.EntityCount); AssertNinjaEntityEqualNinja(ninjaToDelete, ninja); } } - protected List PopulateTableStorageFake(int amountOfNinjaToCreate, string clanName) + + protected NinjaEntity CreateEntity(string clanName) + { + return CreateEntities(1, clanName).First(); + } + + protected IEnumerable CreateEntities(int amountOfNinjaToCreate, string clanName) { - var ninjaList = new List(); for (int i = 0; i < amountOfNinjaToCreate; i++) { var ninja = new NinjaEntity @@ -198,10 +237,8 @@ protected List PopulateTableStorageFake(int amountOfNinjaToCreate, PartitionKey = clanName, RowKey = $"NinjaKey {i}" }; - ninjaList.Add(ninja); + yield return ninja; } - TableStorageFake.AddRange(ninjaList); - return ninjaList; } protected void AssertNinjaEntityEqualNinja(NinjaEntity entity, Ninja ninja) @@ -212,4 +249,16 @@ protected void AssertNinjaEntityEqualNinja(NinjaEntity entity, Ninja ninja) Assert.Equal(entity.Level, ninja.Level); } } + + public static class TableStorageMockExtensions + { + public static NinjaEntity SetupEnforceNinjaExistenceAsync(this Mock> tableStorageMock, string clanName, string ninjaKey, NinjaEntity entityToReturn = null) + { + var entity = entityToReturn ?? new NinjaEntity(); + tableStorageMock + .Setup(x => x.ReadOneAsync(clanName, ninjaKey)) + .ReturnsAsync(entity); + return entity; + } + } } diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaEntityTableStorageRepositoryFake.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaEntityTableStorageRepositoryFake.cs deleted file mode 100644 index 22b4b3d..0000000 --- a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaEntityTableStorageRepositoryFake.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System.Linq; -using System.Collections.Generic; -using ForEvolve.Azure.Storage.Table; -using ForEvolve.Blog.Samples.NinjaApi.Models; -using System.Threading.Tasks; -using System; - -namespace ForEvolve.Blog.Samples.NinjaApi.IntegrationTests -{ - public class NinjaEntityTableStorageRepositoryFake : ITableStorageRepository - { - private List InternalEntities { get; } - private List MergedEntities { get; } - - public NinjaEntityTableStorageRepositoryFake() - { - InternalEntities = new List(); - MergedEntities = new List(); - } - - public async Task InsertOrMergeAsync(NinjaEntity item) - { - var current = await ReadOneAsync(item.PartitionKey, item.RowKey); - if (current != null) - { - current.Level = item.Level; - current.Name = item.Name; - MergedEntities.Add(current); - return current; - } - InternalEntities.Add(item); - return item; - } - - public async Task InsertOrReplaceAsync(NinjaEntity item) - { - var current = await ReadOneAsync(item.PartitionKey, item.RowKey); - if(current != null) - { - InternalEntities.Remove(current); - } - InternalEntities.Add(item); - return item; - } - - public Task> ReadAllAsync() - { - return Task.FromResult(InternalEntities.AsEnumerable()); - } - - public async Task ReadOneAsync(string partitionKey, string rowkey) - { - var item = (await ReadPartitionAsync(partitionKey)) - .FirstOrDefault(x => x.RowKey == rowkey); - return item; - } - - public Task> ReadPartitionAsync(string partitionKey) - { - var items = InternalEntities - .Where(x => x.PartitionKey == partitionKey); - return Task.FromResult(items); - } - - public async Task RemoveAsync(string partitionKey, string rowkey) - { - var item = await ReadOneAsync(partitionKey, rowkey); - InternalEntities.Remove(item); - return item; - } - - public async Task> RemoveAsync(string partitionKey) - { - var items = await ReadPartitionAsync(partitionKey); - InternalEntities.RemoveAll(x => x.PartitionKey == partitionKey); - return items; - } - - internal bool HasBeenMerged(NinjaEntity item) - { - var mergedItem = MergedEntities.FirstOrDefault(x => x.PartitionKey == item.PartitionKey && x.RowKey == item.RowKey); - return mergedItem != null; - } - - internal void AddRange(IEnumerable ninjaCollection) - { - InternalEntities.AddRange(ninjaCollection); - } - - internal int EntityCount => InternalEntities.Count; - - internal NinjaEntity ElementAt(int index) - { - return InternalEntities[index]; - } - } -} diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs index 7dbfb79..89fb0e7 100644 --- a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs +++ b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/StartupTest.cs @@ -46,6 +46,19 @@ public void Should_return_TableStorageSettings() Assert.NotNull(settings.AccountName); Assert.Equal("MyTableName", settings.TableName); } + + [Fact] + public void Should_return_TableStorageRepository_of_NinjaEntity() + { + // Arrange + var serviceProvider = Server.Host.Services; + + // Act + var result = serviceProvider.GetService>(); + + // Assert + Assert.IsType>(result); + } } } } From 84e67aa5cbbb46e732123f53c085c4d1ce11e32e Mon Sep 17 00:00:00 2001 From: Carl-Hugo Marcotte Date: Thu, 31 Aug 2017 17:18:00 -0400 Subject: [PATCH 10/11] Extracted TableStorageMockExtensions to its own file --- .../Extensions/TableStorageMockExtensions.cs | 18 ++++++++++++++++++ .../NinjaControllerTest.cs | 12 ------------ 2 files changed, 18 insertions(+), 12 deletions(-) create mode 100644 11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/Extensions/TableStorageMockExtensions.cs diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/Extensions/TableStorageMockExtensions.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/Extensions/TableStorageMockExtensions.cs new file mode 100644 index 0000000..1886005 --- /dev/null +++ b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/Extensions/TableStorageMockExtensions.cs @@ -0,0 +1,18 @@ +using ForEvolve.Azure.Storage.Table; +using ForEvolve.Blog.Samples.NinjaApi.Models; +using Moq; + +namespace ForEvolve.Blog.Samples.NinjaApi.IntegrationTests +{ + public static class TableStorageMockExtensions + { + public static NinjaEntity SetupEnforceNinjaExistenceAsync(this Mock> tableStorageMock, string clanName, string ninjaKey) + { + var entity = new NinjaEntity(); // Only need to be not null + tableStorageMock + .Setup(x => x.ReadOneAsync(clanName, ninjaKey)) + .ReturnsAsync(entity); + return entity; + } + } +} diff --git a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaControllerTest.cs b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaControllerTest.cs index 08ff905..8e1eff5 100644 --- a/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaControllerTest.cs +++ b/11. NinjaApi - IntegrationTesting/test/ForEvolve.Blog.Samples.NinjaApi.IntegrationTests/NinjaControllerTest.cs @@ -249,16 +249,4 @@ protected void AssertNinjaEntityEqualNinja(NinjaEntity entity, Ninja ninja) Assert.Equal(entity.Level, ninja.Level); } } - - public static class TableStorageMockExtensions - { - public static NinjaEntity SetupEnforceNinjaExistenceAsync(this Mock> tableStorageMock, string clanName, string ninjaKey, NinjaEntity entityToReturn = null) - { - var entity = entityToReturn ?? new NinjaEntity(); - tableStorageMock - .Setup(x => x.ReadOneAsync(clanName, ninjaKey)) - .ReturnsAsync(entity); - return entity; - } - } } From cd505e61653d1410aec5f91feb476e7d9632d2ae Mon Sep 17 00:00:00 2001 From: Carl-Hugo Marcotte Date: Fri, 1 Sep 2017 12:58:39 -0400 Subject: [PATCH 11/11] Updated Part 9 & 10 README --- 10. NinjaApi - NinjaRepository/README.md | 2 +- 9. NinjaApi - NinjaMappingService/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/10. NinjaApi - NinjaRepository/README.md b/10. NinjaApi - NinjaRepository/README.md index d362674..0976423 100644 --- a/10. NinjaApi - NinjaRepository/README.md +++ b/10. NinjaApi - NinjaRepository/README.md @@ -1,4 +1,4 @@ # Dependency Injection This project contains the code sample of the -[Design Patterns: Asp.Net Core Web API, services, and repositories | Part 10: the NinjaRepository and the ForEvolve.Azure](http://www.forevolve.com/en/articles/2017/09/13/design-patterns-web-api-service-and-repository-part-10/) +[Design Patterns: Asp.Net Core Web API, services, and repositories | Part 10: the NinjaRepository and ForEvolve.Azure](http://www.forevolve.com/en/articles/2017/09/14/design-patterns-web-api-service-and-repository-part-10/) article. \ No newline at end of file diff --git a/9. NinjaApi - NinjaMappingService/README.md b/9. NinjaApi - NinjaMappingService/README.md index bdb7438..dbeb236 100644 --- a/9. NinjaApi - NinjaMappingService/README.md +++ b/9. NinjaApi - NinjaMappingService/README.md @@ -1,4 +1,4 @@ # Dependency Injection This project contains the code sample of the -[Design Patterns: Asp.Net Core Web API, services, and repositories | Part 9: the NinjaMappingService](http://www.forevolve.com/en/articles/2017/09/08/design-patterns-web-api-service-and-repository-part-9/) +[Design Patterns: Asp.Net Core Web API, services, and repositories | Part 9: the NinjaMappingService](http://www.forevolve.com/en/articles/2017/09/11/design-patterns-web-api-service-and-repository-part-9/) article. \ No newline at end of file