c# – How to properly mock classes with asynchronous methods in Ninject.MockingKernel?

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.

  1. OS: Windows 10
  2. IDE: VS 2015 Update 3
  3. Platform: .NET Framework 4.6
  4. Ninject: v3.2.2.0 (net46)
  5. Ninject.MockingKernel: v3.2.2.0 (net46)
  6. Ninject.MockingKernel.Moq: v3.2.2.0 (net46)
  7. 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.

Scroll to Top