什么时候使用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
时间: 2024-11-03 11:12:18