首页 > 代码库 > TDD:使用Moq进行Unit Test

TDD:使用Moq进行Unit Test

什么时候使用Moq

对于下面的代码

public class ProductBusiness{    public void Save()    {        try        {            var repository = new ProductRepository();            resository.Save();        }        catch(AException ae)        {            ...        }        catch(BException be)        {            ...        }    }}

如果我们要对ProductBusiness.Save()方法进行UT,那么该怎么做才能让UT应该包含所有的path,即产生不同的exception?

是使用Moq的时候了。

怎么使用Moq进行单元测试

首先,我们要修改我们的代码设计,使其更容易被测试,即所谓的Test Driven Development.

因为我们要测试的是ProductBusiness.Save(),因此我们应该把它与ProductRepository的逻辑进行分离。

 public class ProductBusiness{    public void Save(IProductRepository repository)    {        try        {            resository.Save();        }        catch(AException ae)        {            ...        }        catch(BException be)        {            ...        }    }}public interface IProductRepository{    bool Save();    bool Delete();    bool Update();        IProduct Get(int id);}public interface IProduct{    int Id {get; set;}        string Name { get; set; }}

我们通过参数把ProductRepository传给Save,而不是在里面new。同时,把ProductRepository变成了一个接口。

这样,我们可以使用Moq mock出一个ProductRepository,传给ProductBusiness.Save。虽然IProductRepository有四个方法,但是我们在测试ProductBusiness.Save的时候,只需要IProductRepository的Save方法。Moq也可以使我们仅mock该接口的这一个方法。

[TestMethod]public void SaveTest(){    var productBusiness = new ProductBusiness();        Mock<IProductRepository> mockRepo = new Mock<IProductRepository>();    mockRepo.Setup<bool>(obj => obj.Save()).Throws(new AException("Mock AException"));    productBusiness.Save(mockRepo.Object);}

在UT的第二行,我们创建了一个Mock<IProductRepository>对象,然后第三行,我们改变了Save的behavior,即强制抛出一个AException。

第四行里,我们把这个mock对象传递给了productBusiness.Save()作为参数。

注意,mockRepo是一个IProductRepository的wrapper,mockRepo.Object才是真正的改变了Save方法的behavior的IProductRepository对象。

 

Moq的更多用法,请参考https://github.com/Moq/moq4

 

TDD:使用Moq进行Unit Test