t3chb0t
t3chb0t

Reputation: 18655

JustMock helpers in another class return null in test

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?

Upvotes: 1

Views: 156

Answers (2)

t3chb0t
t3chb0t

Reputation: 18655

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())

Upvotes: 0

vsarunov
vsarunov

Reputation: 1547

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.

Upvotes: 1

Related Questions