JustMock helpers in another class return null in test

147 views Asked by At

I moved the most frequently created mocks into extensions and helper classes to be able to reuse them in several tests. I was very surprised when it turned out that they are appently context dependent and don't work when sitting elsewhere.

This code demonstrates the issue:

void Main()
{
    // Does not get the mock user.
    var db = MockFactory.MockUserDatabase();        
    db.GetUsersAsync().GetAwaiter().GetResult().Dump(); // <-- null

    // This works and gets the mock user.
    var mock = Mock.Create<IUserDatabase>();
    mock
        .Arrange(x => x.GetUsersAsync())
        .Returns(Task.FromResult(new[] { new User { Name = "John" } }));

    mock.GetUsersAsync().GetAwaiter().GetResult().Dump(); // <-- mock user

}

static class MockFactory
{
    public static IUserDatabase MockUserDatabase()
    {
        var mock = Mock.Create<IUserDatabase>();

        mock
            .Arrange(x => x.GetUsersAsync())
            .ReturnsTask(new[] { new User { Name = "John" } });

        return mock;
    }
}

public static class JustMockHelpers
{
    public static IAssertable ReturnsTask<TReturn>(this IAssertable assertable, TReturn value)
    {
        return assertable.Returns(Task.FromResult<TReturn>(value));
    }
}

public interface IUserDatabase
{
    Task<User[]> GetUsersAsync();
}

public class User
{
    public string Name { get; set; }
}

Is there any way I can make the JustMock code encapsulated in other classes work too?

2

There are 2 answers

3
vsarunov On

The problem here is you are using a Static MockFactory and it works when you use it directly not statically. Why Would use a static class if you are still initiating the test data each time and each time you recreate the mock? Either try to have a base testing class with this method and call it base.YourInitialiseMethod() or something like TestFixtures. If you look at documentation of JustMock they always do create inside each test case individually.

0
t3chb0t On

I have found a trick. You can pull it to the same static context with a Func. ReturnsTask still won't cooperate but at least the general arrangement does.

static class MockFactory
{
    public static Func<IUserDatabase> MockUserDatabase
    {
        get
        {
            return () =>
            {
                var mock = Mock.Create<IUserDatabase>();

                mock
                    .Arrange(x => x.GetUsersAsync())
                    .Returns(new[] { new User { Name = "John" } }.ToTask());

                return mock;
            };
        }
    }
}

I turned the other extension around and made it:

public static Task<T> ToTask<T>(this T obj) => Task.FromResult(obj);

Then I just call:

.Returns(new[] { new User { Name = "John" } }.ToTask())