Unit testing 使用Moq模拟返回值的存储库

Unit testing 使用Moq模拟返回值的存储库,unit-testing,nunit,moq,Unit Testing,Nunit,Moq,如何在模拟接受对象的存储库上设置测试方法 这就是我到目前为止所做的: 服务中心 public int AddCountry(string countryName) { Country country = new Country(); country.CountryName = countryName; return geographicsRepository.SaveCountry(country).CountryId; }

如何在模拟接受对象的存储库上设置测试方法

这就是我到目前为止所做的:

服务中心

    public int AddCountry(string countryName)
    {
        Country country = new Country();
        country.CountryName = countryName;
        return geographicsRepository.SaveCountry(country).CountryId;
    }
test.cs

    [Test]
    public void Insert_Country()
    {
        //Setup
        var geographicsRepository = new Mock<IGeographicRepository>();

        geographicsRepository.Setup(x => x.SaveCountry(It.Is<Country>(c => c.CountryName == "Jamaica"))); //How do I return a 1 here?

        GeographicService geoService = new GeographicService(geographicsRepository.Object);

        int id = geoService.AddCountry("Jamaica");

        Assert.AreEqual(1, id);
    }
框架:

  • 努尼特
  • 最小起订量
  • ASP.NET MVC-存储库模式

  • 您的第一次测试应该如下所示:

    [Test]
    public void Insert_Country()
    {
        Mock<IGeographicRepository> geographicsRepository = new Mock<IGeographicRepository>();
        GeographicService geoService = new GeographicService(geographicsRepository.Object);
    
        // Setup Mock
        geographicsRepository
            .Setup(x => x.SaveCountry(It.IsAny<Country>()))
            .Returns(1);
    
        var id = geoService.AddCountry("Jamaica");
    
        Assert.IsInstanceOf<Int32>(id);
        Assert.AreEqual(1, id);
        geographicsRepository.VerifyAll();
    }
    
    [Test]
    public void Insert_Duplicate_Country_Throws_Exception()
    {
        Mock<IGeographicRepository> geographicsRepository = new Mock<IGeographicRepository>();
        GeographicService geoService = new GeographicService(geographicsRepository.Object);
    
        // Setup Mock
        geographicsRepository
            .Setup(x => x.SaveCountry(It.IsAny<Country>()))
            .Throws(new MyException());
    
        try
        {
            var id = geoService.AddCountry("Jamaica");
            Assert.Fail("Exception not thrown");
        }
        catch (MyException)
        {
            geographicsRepository.VerifyAll();
        }
    }
    
    [测试]
    公共无效插入_国家()
    {
    Mock geographicsRepository=new Mock();
    GeographicService geoService=新的GeographicService(geographicsRepository.Object);
    //设置模拟
    地理信息库
    .Setup(x=>x.SaveCountry(It.IsAny()))
    .申报表(1);
    var id=geoService.AddCountry(“牙买加”);
    Assert.IsInstanceOf(id);
    断言.AreEqual(1,id);
    geographicsRepository.VerifyAll();
    }
    
    第二个测试应该如下所示:

    [Test]
    public void Insert_Country()
    {
        Mock<IGeographicRepository> geographicsRepository = new Mock<IGeographicRepository>();
        GeographicService geoService = new GeographicService(geographicsRepository.Object);
    
        // Setup Mock
        geographicsRepository
            .Setup(x => x.SaveCountry(It.IsAny<Country>()))
            .Returns(1);
    
        var id = geoService.AddCountry("Jamaica");
    
        Assert.IsInstanceOf<Int32>(id);
        Assert.AreEqual(1, id);
        geographicsRepository.VerifyAll();
    }
    
    [Test]
    public void Insert_Duplicate_Country_Throws_Exception()
    {
        Mock<IGeographicRepository> geographicsRepository = new Mock<IGeographicRepository>();
        GeographicService geoService = new GeographicService(geographicsRepository.Object);
    
        // Setup Mock
        geographicsRepository
            .Setup(x => x.SaveCountry(It.IsAny<Country>()))
            .Throws(new MyException());
    
        try
        {
            var id = geoService.AddCountry("Jamaica");
            Assert.Fail("Exception not thrown");
        }
        catch (MyException)
        {
            geographicsRepository.VerifyAll();
        }
    }
    
    [测试]
    公共无效插入\重复\国家\抛出\异常()
    {
    Mock geographicsRepository=new Mock();
    GeographicService geoService=新的GeographicService(geographicsRepository.Object);
    //设置模拟
    地理信息库
    .Setup(x=>x.SaveCountry(It.IsAny()))
    .Throws(new MyException());
    尝试
    {
    var id=geoService.AddCountry(“牙买加”);
    Assert.Fail(“未引发异常”);
    }
    捕获(MyException)
    {
    geographicsRepository.VerifyAll();
    }
    }
    
    我认为您可能有点误解了在您提供的两个场景中使用模拟进行测试的目的

    在第一个场景中,您希望测试在通过“牙买加”时是否返回1。这不是一个模拟测试用例,而是一个真实行为的测试用例,因为您希望根据预期的输出(即“牙买加”->1)测试特定的输入。在这种情况下,模拟更有用,可以确保您的服务在内部使用预期的国家/地区调用存储库上的SaveCountry,并从调用中返回值

    设置“SaveCountry”案例,然后在模拟中调用“VerifyAll”是关键。这将断言“SaveCountry”确实与国家“牙买加”一起被调用,并且返回预期值。通过这种方式,您可以确信您的服务已按预期连接到存储库

    [Test]
    public void adding_country_saves_country()
    {
        const int ExpectedCountryId = 666;
    
        var mockRepository = new Mock<IGeographicRepository>();
    
        mockRepository.
          Setup(x => x.SaveCountry(It.Is<Country>(c => c.CountryName == "Jamaica"))).
          Returns(ExpectedCountryId); 
    
        GeographicService service= new GeographicService(mockRepository.Object);
    
        int id = service.AddCountry(new Country("Jamaica"));
    
        mockRepo.VerifyAll();
    
        Assert.AreEqual(ExpectedCountryId, id, "Expected country id.");
    }
    
    [测试]
    公共无效添加国家/地区保存国家/地区()
    {
    const int ExpectedCountryId=666;
    var mockRepository=new Mock();
    模拟存储库。
    设置(x=>x.SaveCountry(It.Is(c=>c.CountryName==“牙买加”))。
    返回(ExpectedCountryId);
    地理服务=新地理服务(mockRepository.Object);
    int id=service.AddCountry(新国家(“牙买加”);
    mockRepo.VerifyAll();
    Assert.AreEqual(ExpectedCountryId,id,“ExpectedCountryId.”);
    }
    

    在第二个场景中,您希望测试在尝试添加重复国家/地区时是否引发异常。使用mock执行此操作没有多大意义,因为您将测试的只是您的mock在添加重复项时的行为,而不是您的实际实现。

    我是否应该调用
    AddCountry(“牙买加”)
    两次,并设置存储库以观察是否两次传递相同的字符串?@Shawn:通常,模拟对象的设计允许开发人员独立测试应用程序层。在本例中,您正在测试独立于DAO的服务层。您应该做的只是检查服务层是否确实调用了正确的方法。据推测,存储库单元测试应该负责验证是否在应该抛出异常的时候抛出异常。好的,这是有意义的。所以本质上,我不需要对该服务进行第二次测试,只需要模拟存储库。谢谢,没问题。为了更好地解释这一思路,请阅读这里:它真正的模拟对象是为独立测试应用程序层而设计的,我同意这一点。但在实际场景中,这种情况不会发生,开发人员希望测试完整的方法及其依赖关系,因此我认为在这种情况下模拟是不合适的。我们还应该为那些维护成本高的方法编写mock,如dbcall等。谢谢。我理解关于不检查值的部分。在您的示例中,不返回值(CountryId)。在AddCountry方法中,它返回存储库的Id。我还应该因为需要而嘲笑返回值吗?@Shawn My appologies-这里太晚了。。。是的,对返回值的模拟应该在那里。我已经更新了我的答案。谢谢。示例越多,我就越了解这些模式:)这可以通过AutoFixture和AutoFixture的Moq自定义进行进一步清理。