Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Microsoft Fakes to Shim Async Task method?

I'm using Microsoft Fakes to Shim an async method that invokes another method to get an implemented DbContext. Because database connection string is not supplied in the Unit Test while the method being invoked inside the async method needs it. Shim will not only skip the method that uses the connection string, but returns a customizable DbContext.

Here is the aysnc method implementation:

public async Task<AccountDataDataContext> GetAccountDataInstance(int accountId)
{
    var account = await this.Accounts.FindAsync(accountId);

    return AccountDataDataContext.GetInstance(account.AccountDataConnectionString);
}

However, I'm not familiar with Shim async method. What I did look like this:

ConfigurationEntities.Fakes.ShimConfigurationDataContext.AllInstances.GetAccountDataInstanceInt32NullableOfInt32 = (x, y, z) => new Task<AccountDataEntities.AccountDataDataContext>(() =>
{
    return new SampleContext();// This is the fake context I created for replacing the AccountDataDataContext.
});

And SampleContext is implementing AccountDataDataContext as follows:

public class SampleContext: AccountDataDataContext
{
    public SampleContext()
    {
        this.Samples = new TestDbSet<Sample>();

        var data = new AccountDataRepository();

        foreach (var item in data.GetFakeSamples())
        {
            this.Samples.Add(item);
        }
    }
}

Below is the code snippet for the test case:

[TestMethod]
public async Task SampleTest()
{
    using (ShimsContext.Create())
    {
        //Arrange
        SamplesController controller = ArrangeHelper(1);// This invokes the Shim code pasted in the second block and returns SamplesController object in this test class

        var accountId = 1;
        var serviceId = 2;

        //Act
        var response = await controller.GetSamples(accountId, serviceId);// The async method is invoked in the GetSamples(int32, int32) method.

        var result = response.ToList();

        //Assert
        Assert.AreEqual(1, result.Count);
        Assert.AreEqual("body 2", result[0].Body);
    }
}

As the result, my test case is running forever. I think I might write the Shim lamdas expression completely wrong.

Any suggestion? Thank you.

like image 844
Ruoyu Jiang Avatar asked Apr 14 '16 11:04

Ruoyu Jiang


1 Answers

You don't want to return a new Task. In fact, you should never, ever use the Task constructor. As I describe on my blog, it has no valid use cases at all.

Instead, use Task.FromResult:

ConfigurationEntities.Fakes.ShimConfigurationDataContext.AllInstances.GetAccountDataInstanceInt32NullableOfInt32 =
    (x, y, z) => Task.FromResult(new SampleContext());

Task also has several other From* methods that are useful for unit testing (e.g., Task.FromException).

like image 126
Stephen Cleary Avatar answered Nov 11 '22 08:11

Stephen Cleary