我正在尝试将TDD应用于我的一个简单项目.一些细节(以及之前的问题)在这里:
TDD:帮助编写Testable类
具体是我有一个PurchaseOrderCollection类,它有一个私有的PurchaseOrders列表(在构造函数中传入),而PurchaseOrders有一个布尔属性IsValid.PurchaseOrderCollection具有属性HasErrors,如果列表中的任何PurchaseOrders将IsValid设置为false,则返回true.这是我想测试的逻辑.
[TestMethod] public void Purchase_Order_Collection_Has_Errors_Is_True_If_Any_Purchase_Order_Has_Is_Valid_False() { Listorders = new List (); orders.Add(new PurchaseOrder(--some values to generate IsValid false--)); orders.Add(new PurchaseOrder(--some values to generate IsValid true--)); PurchaseOrderCollection collection = new PurchaseOrderCollection(orders); Assert.IsTrue(collection.HasErrors); }
这与我之前的问题类似,因为这个测试太过耦合了,我必须知道什么使得PurchaseOrder IsValid为false或者true才能通过测试,而这个测试真的不应该关心.问题是不同的(imo)因为类本身不是问题.
基本上我希望能够在不知道任何有关PurchaseOrder的内容的情况下声明具有IsValid false或true的PurchaseOrder.
根据我有限的TDD知识,这是你使用Stubs或Mocks的东西.我的主要问题是,这是正确的吗?或者我应该使用不同的方法吗?或者我是完全有缺陷的,我只是在写这个测试并且认为它错了?
我最初的想法是只使用某种模拟框架并创建一个始终返回true或false的PurchaseOrder.从我读过的内容来看,我需要声明IsValid是虚拟的.所以我的第二个想法是改变它以添加IPurchaseOrder作为PurchaseOrder的接口,并创建一个始终返回false或true的假PurchaseOrder.这些都是有效的想法吗?
谢谢!
无论是创建存根还是模拟,您都在正确的轨道上.我更喜欢使用Mocking框架.
使用模拟框架的工作原理是你想要模拟你的PurchaseOrder类,从而抽象出它的实现.然后设置调用IsValid的期望值以及调用它时返回此值.
使用Moq的示例,如果您使用的是C#3.0和.NET Framework 3.5:
[TestMethod] public void Purchase_Order_Collection_Has_Errors_Is_True_If_Any_Purchase_Order_Has_Is_Valid_False() { var mockFirstPurchaseOrder = new Mock(); var mockSecondPurchaseOrder = new Mock (); mockFirstPurchaseOrder.Expect(p => p.IsValid).Returns(false).AtMostOnce(); mockSecondPurchaseOrder.Expect(p => p.IsValid).Returns(true).AtMostOnce(); List purchaseOrders = new List (); purchaseOrders.Add(mockFirstPurchaseOrder.Object); purchaseOrders.Add(mockSecondPurchaseOrder.Object); PurchaseOrderCollection collection = new PurchaseOrderCollection(orders); Assert.IsTrue(collection.HasErrors); }
编辑:
这里我使用了一个界面来创建PurchaseOrder的模拟,但你没有.您可以将IsValid标记为虚拟并模拟PurchaseOrder类.我的经验法则是哪种方式首先使用虚拟.只是为了创建一个界面,所以我可以在没有任何架构原因的情况下模拟一个对象,这对我来说是一种代码味道