【问题标题】:How to use moq object in unit testing?如何在单元测试中使用 moq 对象?
【发布时间】:2014-05-02 22:05:50
【问题描述】:

我正在对我的Service layer class(ProductService) 之一进行单元测试。该层为controller class(ProductController) 之一提供DI 工具。对于ProductController 单元测试,已经有一个单元测试类ProductControllerTest。

但是对于单元测试ProductController的服务层(ProductService),我创建了一个新的单元测试类(ProductServiceTest)

但我不知道是否应该创建一个新的单元测试类来进行服务层单元测试。

我也想知道DI(Dependency Injection) and Mocking(MOQ object)在单元测试中的概念。意思是在单元测试中在哪里使用起订量以及何时需要使用?

我已经为 ProductService 的一种操作方法编写了单元测试代码。我想知道它是否正确?

下面是Action Method的代码:-

public class ProductService : IProductService
{
    private readonly IProductDal<Product> _productDal;
    private readonly IUserDal<Users> _userDal;

    public ProductService(IProductDal<Product> ProductDAL)
    {
        _productDal = ProductDAL;
    }


    public List<ProductDto> GetProducts(string SearchInName, string SearchInDescription)
    {
          List<ProductDto> productList = new List<ProductDto>();
          foreach (Product product in _productDal.GetProducts(SearchInName, SearchInDescription))
          {
               productList.Add(Adapter.AdaptOmToDto(product));
          }
          return productList;
    }
}

下面是单元测试(ProductServiceTest)类的一段代码:-

    [TestMethod]
    public void GetProductsTest()
    {
        var productList = new List<ProductDto>();

        // Arrrange            
        var Name = "CreateSave";
        var Description = "CreateSave";

        // Act
        List<ProductDto> output = _productService.GetProducts(Name, Description);

        // Assert       
        Assert.IsNotNull(output);
        Assert.IsInstanceOfType(output, typeof(List<ProductDto>));
    }

有人可以建议我对此类方法进行单元测试的最佳方法吗?

【问题讨论】:

  • 你好去这个链接MSDN我希望它会帮助你

标签: unit-testing asp.net-mvc-4 dependency-injection moq


【解决方案1】:

我也想知道单元测试中DI(依赖注入)和Mocking(MOQ对象)的概念

依赖注入是我们使我们的应用程序遵守Dependency Inversion Principle 的方式,它指出高级模块不应该依赖于低级模块——两者都应该依赖于抽象。依赖抽象为您提供了系统中单元的低耦合,并且能够将抽象依赖的任何实现提供给依赖类。这里是与单元测试相关的部分——您可以提供依赖的模拟实现,这将允许您验证被测单元的行为(参见Mocks Aren't Stubs 文章)。

通过使ProductService 依赖于抽象,您已经做得很好,并且您使用 DI 将抽象实现注入服务。您需要测试服务行为的是注入模拟的抽象实现,并在ProductService 和模拟之间设置预期的交互:

ProductService _productService;
Mock<IProductDal<Product>> _productDalMock;

[TestInitialize]
public void Setup()
{
    // create mock of dependency and pass mocked object to service
    _productDalMock = new Mock<IProductDal<Product>>();
    _productService = new ProductService(productDalMock.Object);
}

[TestMethod]
public void ShouldNotReturnDtosWhenProductsNotFound()
{
    // Arrrange 
    var name = "CreateSave";
    var description = "CreateSave";
    // setup mocked dal to return empty list of products
    // when name and description passed to GetProducts method
    _productDalMock.Setup(d => d.GetProducts(name, description))
                   .Returns(new List<Product>());

    // Act
    List<ProductDto> actual = _productService.GetProducts(name, description);

    // Assert
    Assert.False(actual.Any());
    // verify all setups of mocked dal were called by service
    _productDalMock.VerifyAll();
}

正如您在上面的测试中看到的,您可以检查产品服务是否使用正确的参数调用其依赖项,并且您可以设置依赖项返回服务的数据。对于下一个测试,您可以设置模拟以返回预定义产品的列表。然后您将验证服务是否返回了适当的 dto。

【讨论】:

  • 感谢您的建议 Sergey。但我想知道当我们在服务类构造函数中传递 moq 对象时,我们能否从 DAL 类中获取记录?如您所知,我们已将 moq 对象传递给构造函数,在这种情况下,我没有在我们的“实际”对象中获得任何记录。我调试了代码并得到了,一旦在调用 GetProducts 方法时控制权进入 DAL 类,DAL 对象就是返回不获取记录。
  • @Pawan 您在“实际”对象中获得的记录与您设置返回的记录完全相同。如果您设置 mock 以返回空列表,它将向服务返回空列表。如果您将提供一些其他列表.Returns(new List&lt;Product&gt; { new Product(), new Product() }),那么这两个产品将返回服务
  • 谢尔盖感谢您的回答。我明白了,意思是当我们使用最小起订量对象时,它只是绕过真实对象并返回我们创建的对象。但是我想知道如果需要测试真实对象我们需要做什么?我们应该测试实物吗?
  • @Pawan 实际上您确实在测试真实对象 - ProductService 是真实的,这是您的 SUT(被测系统)。当您进行 unit-testing 时,您的 SUT 应该是真实的,并且它的所有依赖项都被模拟/存根。如果有多个真实对象,那么您正在进行集成测试。如果测试中的真实对象少于一个,那么测试是无用的:)
  • 这对我很有帮助。感谢您的回答@Sergey。我对单元测试还有一些疑问:->> 单元测试中的 SUT 应该是什么?表示哪个代码区域是 SUT,哪个是依赖项?
猜你喜欢
  • 1970-01-01
  • 2011-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-30
  • 1970-01-01
  • 2012-06-01
相关资源
最近更新 更多