设置我的存储库时,我试图返回一个Account对象。它应该从用户名等于参数的List返回此对象。
但是我得到了例外
“System.String”类型的对象无法转换为“IncrediStaff.DataAccess.Models.Account”类型。
[TestInitialize]
public void Setup()
{
var repository = new Mock<IAccountRepository>();
var accounts = new List<Account>
{
new Account { AccountId = 1, Username = "John", Hash = "9f3Iv0NW9Jr3l+EmOS/zWCPe96k=", Salt = "y7qwIY0ep8aHiiSwl57dt4ueuCo=" }, // Password is, "TestPassword"
new Account { AccountId = 2, Username = "Ryan", Hash = "63mnR/gbFIIU6vGEFqoY5H1QCCI=", Salt = "xi/lkLFqPPTR5Q9rX3m/PJ4FH0rECyalYdyRJ6pCpfE=" }, // Password is, "NewPassword"
new Account { AccountId = 3, Username = "Sarah", Hash = null, Salt = null, FirstLogin = 1 }
};
repository.Setup(x => x.GetAccount(It.IsAny<string>()))
.Returns<Account>(r => accounts.FirstOrDefault(x => x.Username == It.IsAny<string>()));
_service = new AccountService(repository.Object);
}
[TestMethod]
[TestCategory("Accounts")]
public void UserPasswordIsCorrect()
{
Assert.IsTrue(_service.Login("John", "TestPassword"));
}
如果我返回一个Account对象,则测试通过。
repository.Setup(x => x.GetAccount(It.IsAny<string>()))
.Returns(new Account
{
AccountId = 1,
Username = "John",
Hash = "9f3Iv0NW9Jr3l+EmOS/zWCPe96k=",
Salt = "y7qwIY0ep8aHiiSwl57dt4ueuCo="
});
我不确定为什么它不能从列表中返回单个对象。此外,我有另一个使用相同列表和测试通过的设置。我不确定为什么这样做而另一个没有。
repository.Setup(r => r.SelectIfUsernameExists(It.IsAny<string>()))
.Returns<string>(username => accounts.Exists(r => r.Username == username));
答案 0 :(得分:1)
您应该检查此案例的来源以查看您的问题: https://github.com/moq/moq4/blob/b2cf2d303ea6644fda2eaf10bad43c88c05b395f/Source/Language/IReturns.cs https://github.com/moq/moq4/blob/b2cf2d303ea6644fda2eaf10bad43c88c05b395f/Source/MethodCallReturn.cs
具体来说,这一个:
IReturnsResult<TMock> Returns<T>(Func<T, TResult> valueFunction);
文档说,T是:
被调用方法的参数类型
因此,返回的泛型参数中的T类型实际上是第一个参数的类型,它被传递给您在之前的设置方法中模拟的函数。
您的设置确实x.GetAccount(It.IsAny<string>())
- 它模拟了具有签名Account GetAccount(string name)
的方法,因此调用的方法采用类型为string
的一个参数。
因此,当您执行Returns
时,您的IDE已经知道返回参数的类型 - 它与文档一样TResult
。如果您没有指定泛型参数,它将始终返回您在.Returns()
中定义的对象。但是,如果要根据.Setup()
对其进行参数化,则需要明确说明在您正在模拟的函数内传递的顺序是什么。
在您的情况下,您传递的string
类型只有1个参数 - 它的用户名。因此,要进行参数绑定,必须将其类型 - string
- 作为通用参数传递。
这样做也是为了让您可以为.Returns
方法提供多个参数,例如:
.Returns<string, int, DateTime>((string str, int i, DateTime date) => ...);
答案 1 :(得分:0)
It.IsAny<string>()
子句中的 Returns
将始终返回null。见this answer。所以你的
accounts.FirstOrDefault(x => x.Username == It.IsAny<string>())
真的是
accounts.FirstOrDefault(x => x.Username == null)
将返回null。
相反,你需要像
这样的东西accounts.FirstOrDefault(x => x.Username == "John")