I am trying to implement Dependency Injection in Xunit test for AppService. Ideal goal is to run the original application program Startup/configuration, and use any dependency injection that was in Startup, instead of reinitializing all the DI again in my test, thats the whole Goal in question.
Update: Mohsen's answer is close. Need to update couple syntax/requirement errors to work.
For some reason, original application works and can call Department App Service. However, it cannot call in Xunit. Finally got Testserver working using Startup and Configuration from original application. Now receiving error below:
Message: The following constructor parameters did not have matching fixture data: IDepartmentAppService departmentAppService
namespace Testing.IntegrationTests
{
public class DepartmentAppServiceTest
{
public DBContext context;
public IDepartmentAppService departmentAppService;
public DepartmentAppServiceTest(IDepartmentAppService departmentAppService)
{
this.departmentAppService = departmentAppService;
}
[Fact]
public async Task Get_DepartmentById_Are_Equal()
{
var options = new DbContextOptionsBuilder<SharedServicesContext>()
.UseInMemoryDatabase(databaseName: "TestDatabase")
.Options;
context = new DBContext(options);
TestServer _server = new TestServer(new WebHostBuilder()
.UseContentRoot("C:\\OriginalApplication")
.UseEnvironment("Development")
.UseConfiguration(new ConfigurationBuilder()
.SetBasePath("C:\\OriginalApplication")
.AddJsonFile("appsettings.json")
.Build()).UseStartup<Startup>());
context.Department.Add(new Department { DepartmentId = 2, DepartmentCode = "123", DepartmentName = "ABC" });
context.SaveChanges();
var departmentDto = await departmentAppService.GetDepartmentById(2);
Assert.Equal("123", departmentDto.DepartmentCode);
}
}
}
I am receiving this error:
Message: The following constructor parameters did not have matching fixture data: IDepartmentAppService departmentAppService
Need to use Dependency injection in testing just like real application. Original application does this. Answers below are not currently sufficient , one uses mocking which is not current goal, other answer uses Controller which bypass question purpose.
Note: IDepartmentAppService has dependency on IDepartmentRepository which is also injected in Startup class, and Automapper dependencies. This is why calling the whole startup class.
Good Resources:
how to unit test asp.net core application with constructor dependency injection
Use Custom Web Application Factory and ServiceProvider.GetRequiredService below, feel free to edit and optimize answer
CustomWebApplicationFactory:
Integration Test:
Resources:
https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.2
https://fullstackmark.com/post/20/painless-integration-testing-with-aspnet-core-web-api
When you are testing. You need to use mocking libraries or Inject your service directly on contructor ie.
You are mixing unit test with integration test.
TestServer
is for integration test and if you want to reuseStartup
class to avoid register dependencies again, you should useHttpClient
and make HTTP call to controller and action that useIDepartmentAppService
.If you want do unit test, you need to setup DI and register all needed dependencies to test
IDepartmentAppService
.Using DI through Test Fixture:
Using dependency injection with unit test is not good idea and you should avoid that. by the way if you want don't repeat your self for registering dependencies, you can wrap your DI configuration in another class and use that class anywhere you want.
Using DI through Startup.cs:
in
Startup
class andConfigureServices
method just useIocConfig
class:if you don't want use
IocConfig
class, changeConfigureServices
inStartup
class:and in test project reuse
IocConfig
orStartup
class:and in test method: