从列表中返回单个对象

时间:2016-03-04 10:14:03

标签: c# moq

设置我的存储库时,我试图返回一个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));

2 个答案:

答案 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")