Question:
There is a class that Ninject
uses to get a repository instance:
public class ClosedClass
{
public String DoWork()
{
var repo = AppStatic.Kernel.Get<IRepo>();
return repo.GetData();
}
public async Task<String> DoWorkAsync()
{
var repo = AppStatic.Kernel.Get<IRepo>();
return await repo.GetDataAsync();
}
}
As you can see from the code, a specific instance of the class that implements IRepo
each instance of the ClosedClass
class from the Ninject
core, an instance of which is stored in a static public field of the static class AppStatic
. Here, in fact, is the class code:
public static class AppStatic
{
public static IKernel Kernel { get; private set; }
static AppStatic()
{
Kernel = new StandardKernel();
}
public static void SetKernel(IKernel kernelInstance)
{
Kernel = kernelInstance;
}
}
The ClosedClass
must be tested with MSTest + Ninject + Ninject.MockingKernel + Moq, which tests both methods (synchronous DoWork()
and asynchronous DoWorkAsync()
). Actually, there are no problems with testing the synchronous method. An instance of the class is created, then the core Niject
, which allows you to bind mocks to interfaces, on the specified mock, in fact, the desired value is indicated:
[TestMethod]
public void TestSync()
{
var c = new SAMPLEMOQ.ClosedClass();
var kernel = new MoqMockingKernel();
kernel
.GetMock<IRepo>()
.Setup(m => m.GetData())
.Returns("FAKE");
AppStatic.SetKernel(kernel);
Trace.WriteLine(c.DoWork());
}
As a result of the test execution, the string FAKE
is displayed in output
– great! However, when testing the asynchronous DoWorkAsync()
method DoWorkAsync()
similar manner, the test simply starts execution and does not stop until I cancel the execution myself. Unit test code for the asynchronous DoWorkAsync()
method:
[TestMethod]
public async Task TestASync()
{
var c = new SAMPLEMOQ.ClosedClass();
var kernel = new MoqMockingKernel();
kernel
.GetMock<IRepo>()
.Setup(m => m.GetDataAsync())
.Returns(new Task<String>(() => "Fake"));
AppStatic.SetKernel(kernel);
Trace.WriteLine(await c.DoWorkAsync());
}
The question is: why is this test not being executed, and what does it not even give an error?
PS : I do NOT run the tests in parallel, each one separately.
- OS: Windows 10
- IDE: VS 2015 Update 3
- Platform: .NET Framework 4.6
- Ninject: v3.2.2.0 (net46)
- Ninject.MockingKernel: v3.2.2.0 (net46)
- Ninject.MockingKernel.Moq: v3.2.2.0 (net46)
- Moq: v4.5.2.1 (net46)
Answer:
Try to replace
kernel
.GetMock<IRepo>()
.Setup(m => m.GetDataAsync())
.Returns(new Task<String>(() => "Fake"));
on
kernel
.GetMock<IRepo>()
.Setup(m => m.GetDataAsync())
.Returns(Task.FromResult("Fake"));
or
kernel
.GetMock<IRepo>()
.Setup(m => m.GetDataAsync())
.Returns(
async () =>
{
await Task.Delay(20);
return "Fake";
});
(whichever is required).
Here's the thing. If you remove all the harness, then in fact there is
await new Task<String>(() => "Fake");
However, new Task(...)
creates a task that has not been started (with the Created status), this await
will not complete.