Reputation: 55
new at unit testing and .NET Core (1.0.1), looking for some help.
Im looking to unit test a few classes that are using the .NET Core dependency injection pattern. Application runs fine, but when trying to run NUnit tests with the classes that require DI, error outputs:
No handler for message 'TestExecution.TestResult' when at state 'TestExecutionSentTestRunnerProcessStartInfo' An exception occurred while invoking executor 'executor://dotnetunittestexecutor/v1': Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host. An existing connection was forcibly closed by the remote host
Haven't had a lot of luck with searching that error, or any documentation around using DI with NUnit. I have a feeling I'm not suppose to config like this. However, a few settings (connection strings etc) live in the appsettings.json file which get injected via Startup.cs. How would I access these in the NUnit classes?
My Startup.cs, gets the connection string and preps for DI
public void ConfigureServices(IServiceCollection services)
{
//other Configurations happen here
//get the connection string values from appsettings.json
services.Configure<ConnectionStrings>(Configuration.GetSection("ConnectionStrings"));
//Classes that get DI'd
services.AddSingleton<IMyDAL, MyDal>();
services.AddSingleton<MyBLL>();
}
MyDAL requires configurations to be injected, available via Startup.cs:
public class MyDAL : IMyDAL
{
private readonly string _dbConnectionString;
public MyDAL(IOptions<ConnectionStrings> connectionString)
{
_dbConnectionString = connectionString.Value.ConnectionString;
}
public bool DoDALStuff() { ... }
}
MyBLL class requires IMyDAL to be injected:
public class MyBLL
{
public readonly IMyDAL _myDAL;
public MyBLL(IMyDAL myDAL)
{
_myDAL = myDAL;
}
public bool DoBLLStuff() { ... }
}
My NUnit class requires the BLL injection to test:
[TestFixture]
public class BLLTest
{
public MyBLL _myBLL;
public BLLTest(MyBLL myBLL)
{
_myBLL = myBLL;
}
[Test]
public void TestTheBLL()
{
Assert.IsTrue(_myBLL.DoBLLStuff() == true)
}
}
This is how my regular program flow looks like, but I might be approaching it in the wrong way trying to implement this unit test in the same DI fashion. If I remove any DI/constructor code in the test class, the tests run fine, but I still need to test the methods that require DI inside the BLL. Anyone know how I can get the DI'd objects into my test class to use? Am I using an incorrect approach?
Upvotes: 1
Views: 809
Reputation: 7804
I'm using xUnit, I didn't have time yet to dive into Nunit.
Warning (source)
dotnet-test-nunit is still an alpha release
I believe you have an issue with your test runner. You should start by reading about Integration testing with ASP.NET Core. Examples are only with xUnit though.
Here is also a blog post how to perform this with Nunit.
What is important is that you run your test project, not directly your web project (even if this one is referenced and used by the test project).
Because of that, you need another JSON settings file inside your test project which will be used instead of the one in your web project. You certainly want other configuration in testing mode than in Dev or Prod.
In case if unit testing you would prefer calling your classes' methods directly but if you are in a context of integration testing you should call your controllers like any other client (JavaScript, mobile app...etc) would do.
To do so, you can create TestServer then a client from your and finally send normal HTTP request like this:
var webHostBuilder = new WebHostBuilder().UseEnvironment("Testing").UseStartup<Startup>();
var host = new TestServer(webHostBuilder);
var client = host.CreateClient();
var response = await client.PostAsync(endpoint, form);
In this example endpoint
is simply this URL and form
is a MultipartFormDataContent
because I'm posting a file
Upvotes: 0
Reputation: 247018
Am I using an incorrect approach?
Yes. You misunderstand the definition of unit testing. You want to test the BLL in isolation. not against actual implementations as that would be an integration test.
how can I get the DI'd objects into my test class to use?
You create fake implementations of your dependencies or use a mocking framework of your choice to mock the dependencies for the unit test.
[TestFixture]
public class BLLTest {
private MyBLL _myBLL;
public BLLTest() {
//Arrange
var dalMock = new Mock<IMyDAL>();
dalMock.Setup(x => x.DoDALStuff()).Returns(true);//setup expected behavior
//...setup other expected behavior of dependencies
//create the target of unit test (class under test)
_myBLL = new MyBLL(dalMock.Object); //manually injecting dependency
}
[Test]
public void TestTheBLL() {
//Act
var result = _myBLL.DoBLLStuff();
//Assert
Assert.IsTrue(result);
}
}
this is just a basic example to get you started. there are many other ways to do this. you should do some more research into unit testing
Upvotes: 1