如何设置根据参数值动态 returns 结果的模拟?
How do I setup a mock that dynamically returns results based on a parameter's value?
我正在尝试测试 API 控制器方法是否仅 returns 用户(加上一些与此处无关的其他状态)匹配基于 Name
where Name = FirstName + ' ' + LastName
。
我有一个公开了 GetUsersByName(name)
方法的存储库。我想为该存储库方法模拟一个设置,该方法将 return 一个 List<UserModel>
包含与某些存根用户列表 (this.testUsers
) 中的名称标准匹配的用户。
我试过以下方法:
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() );
但我不知道如何将 Contains 子句与我告诉 moq 匹配的 IsAny<string>
联系起来。
这可能吗?我怀疑我需要为 IsAny 提供一个参数,但我找不到任何类似的例子。
是的,这是可能的。您可以使用 Returns<string>
其中
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) );
长答案
我能够构建一个示例测试来重现您所追求的。
[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; }
}
}
我正在尝试测试 API 控制器方法是否仅 returns 用户(加上一些与此处无关的其他状态)匹配基于 Name
where Name = FirstName + ' ' + LastName
。
我有一个公开了 GetUsersByName(name)
方法的存储库。我想为该存储库方法模拟一个设置,该方法将 return 一个 List<UserModel>
包含与某些存根用户列表 (this.testUsers
) 中的名称标准匹配的用户。
我试过以下方法:
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() );
但我不知道如何将 Contains 子句与我告诉 moq 匹配的 IsAny<string>
联系起来。
这可能吗?我怀疑我需要为 IsAny 提供一个参数,但我找不到任何类似的例子。
是的,这是可能的。您可以使用 Returns<string>
其中
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) );
长答案
我能够构建一个示例测试来重现您所追求的。
[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; }
}
}