Test library for integration test make easy and this library is fully tested!
- Replace to memory cache for
IDistributedCache
- Replace to InMemoryDb Easily for your DbContext
- Replace internal service to your own object.
- Change ASP.NET Core host environment value(like
Development
,Production
) - Mock/Fake internal service using by Moq, FakeItEasy, NSubstitute
- Provide build api for writing testing code declarative.
- Getting/Using service after init the test service.
- Provide hooks like
SetupFixture
,Configure*
Methods. - Fake Authentication!!
- Verify your service registration for your conditional registration logic. π
First of all, you have to install this package like below in your project.
dotnet add packge AspNetCore.EasyTesting
And you can create SUT(Short word of System Under Test) object of your Startup class.
using var sut = new SystemUnderTest<Startup>(); // That's all!
If you want to replace your own services to fake service and check response data. Write code like below.
sut.Replace<IYourOwnService>(new FakeService());
var client = sut.CreateHttpClient();
var response = await client.GetAsync("path/to/your/api");
resopnse.ShouldBeOk<YourApiResponse>(apiResponse => {
apiResponse.Field.Should().NotBeEmpty();
});
And this framework is not depends on ANY test framework. What you want, you can use this library for writing integration test easily! :')
If you want to change your DbContext connection with in-memory db-context? You don't need to separate environment in your api project!
Just add package and call ReplaceInMemoryDbContext<TDbContext>
or ReplaceSqliteInMemoryDbContext<TDbContext>
!
dotnet add package AspNetCore.EasyTesting.EntityFrameworkCore
sut.ReplaceInMemoryDbContext<SampleDb>() // Replace your registered both `DbContextOptions<TDbContext>` and `DbContextOptions`
.SetupFixture<SampleDb>(async db =>
{
db.SampleDataEntities.Add(new SampleDataEntity());
await db.SaveChangesAsync();
});
Note that if there are no any specific database name about ReplaceInMemoryDbContext
, the database name is assigned Guid.NewGuid().ToString()
to prevent fail test when parallel test run environment.
Use ReplaceDistributedInMemoryCache
If you want to replace distributed cache with memory cache
sut.ReplaceDistributedInMemoryCache()
.CreateClient();
If you want to replace your own service with mock/fake object.
dotnet add package AspNetCore.EasyTesting.[Moq/FakeItEasy/NSubstitute]
Note that, how many you call replace fake/mock service method, this create library only once and re-use fake/mock object. that mean, you can write mocking chaining code elegantly. ;)
// All cases is same!
var mockService = sut.MockService<ISampleService>();
sut.MockService<ISampleService>(out var mock);
sut.MockService<ISampleService>(mock => mock
.Setup(service => service.GetSampleDate())
.Returns("Action mocked!"))
// Verify helper
sut.VerifyCallOnce<ISampleService>(service => service.GetSampleDate());
sut.VerifyCall<ISampleService>(service => service.GetSampleDate(), Times.Once());
// Dummy service
sut.ReplaceDummyService<ISampleService>();
// Replace fake service
var fakeService = sut.FakeService<ISampleService>();
sut.FakeService<ISampleService>(out var fakeService);
sut.FakeService<ISampleService>(service => A
.CallTo(() => service.GetSampleDate())
.Returns("MockedData"))
// Take registered fake service
var fakeService = sut.GetFakeService<ISampleService>();
sut.UseFakeService<ISampleService>(service => A.CallTo(() => service.GetSampleDate()).MustHaveHappend());
// Replace service with substitute
sut.ReplaceWithSubstitute<ISampleService>(out var mockedService);
sut.ReplaceWithSubstitute<ISampleService>(substitute => /* setup */);
var substitute = sut.ReplaceWithSubstitute<ISampleService>();
// Verify
sut.GetSubstitute<ISampleService>().Received().GetSampleDate();
sut.UseSubstitute<ISampleService>(substitute => substitute.Received().GetSampleDate());
sut.ReplaceService<ISampleService, FakeSampleServic>();
sut.ReplaceService<ISampleService>(new FakeSampleService()); // It will be always registered as singleton.
Use SystemUnderTest.UsingServiceAsync
or SystemUnderTest.UsingService
methods for use internal service.
await sut.UsingServiceAsync<ISampleService>(async service => {
var updated = await service.GetSameplAsync(OriginalFixtureId);
updated.Data.Should().Be("Newer Sample Data");
});
Use SystemUnderTest.VerifyRegisteredLifeTimeOfService
to verify to register your application service lifetime rightly.
var sut = new SystemUnderTest<Startup>();
sut.VerifyRegisteredLifeTimeOfService<ISampleService>(ServiceLifetime.Scoped);
Use VerifyRegisteredImplementationTypeOfService
to verify implementation type registration for service type
when you have conditional service registration logic on startup class.
// Given
var sut = new SystemUnderTest<Startup>();
sut.UseProductionEnvironment();
// When
sut.CreateClient();
// Then
sut.VerifyRegisteredImplementationTypeOfService<ISampleService, ProductionSampleService>();
var client = new SystemUnderTest<Startup>()
.UseProductionEnvironment()
.CreateClient();
UseEnvironment
UseDevelopmentEnvironment
UseStagingEnvironment
UseProductionEnvironment
SystemUnderTest provide delegate methods of IWebHostBuilder to allow fully customization of your way. Check out below methods.
SystemUnderTest.ConfigureServices
SystemUnderTest.ConfigureAppConfiguration
SystemUnderTest.UseSetting
SystemUnderTest.SetupWebHostBuilder
We can do fake authentication handler easily through call few method. But It's not recommended for custom complex implementation of authentication process.
usnig var sut = new SystemUnderTest<Startup>();
// this replace disable defualt original authentication handler with fake authentication handler
var httpClient = sut.NoUserAuthentication()
// .AllowAuthentication("Bearer", new ClaimsPrincipal(/* configure test user principal */)) for faking specific authentication scheme.
// .DenyAuthentication() for test unauthorized call
.CreateClient();
// Now you can call any authorized actions
This library provide you four type methods.
NoUserAuthentication
: When server couldn't find authentication related parts(Cookie, Token, JWT ... etc) from http call.DenyAuthentication
: When server found authentication related parts But it's invalidAllowAuthentication
: When server found valid authentication related parts and can makeIPrincipal
FakeAuthentication
: What you want, just call this method and provide valid ticket or principal instance.
If you don't provide sheme
parameter, it will use DefaultScheme
to fake that is already configured in Startup.cs
by your hand. π
services.AddAuthentication("Bearer") // "Bearer" scheme is default authentication scheme.
Note that if you want to use your own IIdentity
when fake authentication handler for some scheme.
IIdentity.IsAuthenticated
should return true
. if it is not, every call is denied by ASP.NET Core authentication middleware.
This is just simple grpc support for creating grpc client easily.
dotnet add package AspNetCore.EasyTesting.Grpc
CreateGrpcChannel
: create grpc channel for creating grpc client.CreateGrpcClient<T>
:T
is generated grpc client by protoc.
usign var client = new SystemUnderTest<Startup>()
.UseProductionEnvironment()
.CreateGrpcClient<SomeServiceClient>();
await client.DoSomethingAsync(new { Property = 1 });
ReplaceConfigureOptions
: Replace registered configure options. if you used custom configure some option class in startup class.ReplaceNamedConfigureOptions
: Like above but just for named options.DisableOptionValidations
: Remove all options validators aboutTOptions
DisableOptionDataAnnotationValidation
: Disable only data annotation validation.VerifyRegistrationByCondition
: Verify service registration by condition expression.OverrideAppConfiguration
overloadsReplaceLoggerFactory
: Replace logger factory to generating custom logger.- for example : checkout XUnit test sample
DisableStartupFilters
,DisableStartupFilter<TImplementationFilter>
: Remove service registrations ofIStartFilter
RemoveSingleBy
,RemoveAllBy
,Remove
,RemoveAll
: Remove service or implementation types.VerifyNoRegistrationByCondition
,VerifyNoRegistration
: Verify there are no registration of condition or service type.
Visit this library test project. You can see every cases to use this library.
MIT License
Copyright (c) 2021 WDWWW
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.