Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I setup a mock that dynamically returns results based on a parameter's value?

I'm trying to test that an API controller method only returns users (plus some additional states which aren't relevant here) which match based on Name where Name = FirstName + ' ' + LastName.

I have a repository which exposes a GetUsersByName(name) method. I want to mock up a setup for that repository method which will return a List<UserModel> containing users which match the name criteria from some stubbed list of users (this.testUsers).

I've tried the following:

this.mockUserReposiotry.Setup(r => r.GetAllUsersByName(It.IsAny<string>()))
    .Returns(this.mockUtilities.MockUpUserModel(this.testUsers).Where(u => string.Concat(
        u.firstName, " ", u.lastName)
        .ToLower().Contains() );

but I don't know how to tie the Contains clause back to the IsAny<string> that I'm telling moq to match on.

Is this possible? I suspect that I need to provide IsAny with a parameter, but I can't find any similar examples.

like image 295
Necoras Avatar asked Sep 05 '25 05:09

Necoras


1 Answers

Yes it is possible. You can use Returns<string> which

Specifies a function that will calculate the value to return from the method, retrieving the arguments for the invocation

this.mockUserReposiotry.Setup(r => r.GetAllUsersByName(It.IsAny<string>()))
    .Returns<string>(originalParameter => this.mockUtilities.MockUpUserModel(this.testUsers).Where(u => string.Concat(
        u.firstName, " ", u.lastName)
        .ToLower().Contains(originalParameter) );

Long Answer

I was able to construct an example test to recreate what you are after.

[TestClass]
public class DynamicResultsTests {
    List<UserModel> testUsers = new List<UserModel>();
    string[] names = new[] { "John Doe", "Jane Doe", "Jack Sprat", "John Smith", "Mary Jane" };

    [TestInitialize]
    public void Init() {
        testUsers = names.Select(n => {
            var tokens = n.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);

            return new UserModel { firstName = tokens[0], lastName = tokens[1] };
        }).ToList();
    }

    [TestMethod]
    public void Test_ShouldDynamicallyReturnResultsBasedOnParameterValue() {
        //Arrange
        string parameterValue = "john";

        Func<string, UserModel, bool> predicate = (s, u) => string
                .Join(" ", u.firstName, u.lastName)
                .IndexOf(s, StringComparison.InvariantCultureIgnoreCase) > -1;

        Func<string, List<UserModel>> valueFunction = s =>
            this.testUsers.Where(u => predicate(s, u)).ToList();

        var mockUserRepository = new Mock<IUserRepository>();
        mockUserRepository
            .Setup(r => r.GetAllUsersByName(It.IsAny<string>()))
            .Returns<string>(valueFunction);

        var repository = mockUserRepository.Object;

        //Act
        var users = repository.GetAllUsersByName(parameterValue);

        //Assert (There should be 2 results that match john)
        users.Should().NotBeNull();
        users.Should().NotBeEmpty();
        users.Count().Should().Be(2);
    }

    public interface IUserRepository {
        List<UserModel> GetAllUsersByName(string name);
    }

    public class UserModel {
        public string firstName { get; set; }
        public string lastName { get; set; }
    }
}
like image 143
Nkosi Avatar answered Sep 07 '25 21:09

Nkosi