Moq - 如何从方法中返回一个模拟对象?

3

我是Moq的新手,希望不仅在单元测试中使用它,而且在代码中也能运用自如。

考虑到这个实体:

 namespace TestBed.Domain.Entities
 {
    public class Person
    {
        public string LastName { get; set; }
        public string FirstName { get; set; }
        public string PhoneNumber { get; set; }
        public string JobTitle { get; set; }
    }
 }

还有这个抽象存储库:

using TestBed.Domain.Entities;

namespace TestBed.Domain.Abstract
{
    public interface IPersonRepository
    {
        Person GetPerson();
    }
}

我想使用Moq来填充一个虚拟的人员对象,并将填充后的“对象”传递到存储库方法之外。我该如何做?

using TestBed.Domain.Abstract;
using TestBed.Domain.Entities;
using Moq;

namespace TestBed.Domain.Concrete
{
    public class MockPersonReqpository
    {
        Person GetPerson()
        {
            Mock<IPersonRepository> mock = new Mock<IPersonRepository>();
            mock.Setup(m => m.GetPerson()).Returns(new Person()
                                                       {
                                                           FirstName = "Joe",
                                                           LastName = "Smith",
                                                           PhoneNumber = "555-555-5555"
                                                       });
            return mock.Object // NO
        }

    }
}
2个回答

11
根据您在@Daniel答案下的评论,似乎您只需要模拟存储库本身。您仍然希望返回一个正确的“Person”对象,只是您不关心存储库实际上是如何检索该人员以用于测试目的的。
我也不理解您在其他地方使用Moq的评论。Moq的整个目的是为了在测试过程中伪造实际对象(可能比这更好说,但这就是要点)。
由于我不知道您要测试的确切内容,因此我将给出一个微不足道的示例:
[TestMethod]
public void WhenValidRequest_ThenReturnSuccess()
{
    Mock<IPersonRepository> personRepository = new Mock<IPersonRepository>();
    personRepository.Setup(r => r.GetPerson()).Returns(
        new Person() 
        { 
            FirstName = "Joe",
            LastName = "Smith"
            /*...*/
        });

    Foo objectUnderTest = new Foo(personRepository.Object);

    bool result = objectUnderTest.MakeRequest(); 
    // Call method using the person repository that you want to test.
    // You don't actually care how the repository works, you just want to return a success 
    // boolean when a person exists for that request.

    Assert.IsTrue(result);
} 

谢谢。我原本以为 var mock = new Mock<T>() 会产生与 var mock = new Mock<T>.Setup() 相同的结果类型。但事实并非如此。所以,我不应该在同一个调用中尝试构造和操作。 - testpattern

4

mock.Object返回一个IPersonRepository类型的模拟对象。GetPerson()方法的返回类型期望一个Person类型的对象。

另一件事是你没有为Person创建一个模拟对象,所以我不明白这段代码的意义。我不确定你所说的“dummy”是什么意思,但你也可以这样做:

Person GetPerson()
{
    return new Person()
                       {
                           FirstName = "Joe",
                           LastName = "Smith",
                           PhoneNumber = "555-555-5555"
                       };
}

我知道我可以这样做,但我想创建一个模拟的IPersonRepository,然后再创建一个数据库EntityFramework的EFProductDatabase,其中GetPerson方法返回真实数据。这样做有意义吗?我需要为Person创建一个模拟对象还是只需要为Repository创建一个模拟对象?我如何使用Moq来实现我想要的效果?谢谢! - Sam Gentile
依我看,Moq是一种测试辅助工具,它可以模拟所有依赖项,以便您可以测试被测代码的逻辑。您可以手动执行Moq所做的所有操作(模拟和存根),Moq只是使其更容易。Mock是一种断言对象是否按预期与Mock进行交互的方法。在您的情况下,如果我理解正确,您只想创建一个带有一些虚假数据的人吗?您不需要Moq。只需创建一个返回带有一些虚假数据的Person的FakePersonRepository即可。 - Daniel Lee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接