这是我的第一个问题所以请善待! :)
我要做的是为管理器类编写一些测试,在构造期间将单个项类的许多新实例添加到列表中。在此管理器类中调用UpdateAllItems时,目的是迭代列表并对每个项目调用Increment。
经理类是我的代码,但单项类不是,所以我无法修改它。
我使用NUnit作为测试框架,并开始使用Moq。因为经理类使用单项类我认为我需要使用Moq所以我只测试经理,而不是单项。
如何为UpdateAllItems方法编写测试? (从技术上讲,我应该首先编写我知道的测试。)
以下是一些示例代码,可以大致了解我正在使用的内容......
public class SingleItem_CodeCantBeModified
{
public int CurrentValue { get; private set; }
public SingleItem_CodeCantBeModified(int startValue)
{
CurrentValue = startValue;
}
public void Increment()
{
CurrentValue++;
}
}
public class SingleItemManager
{
List<SingleItem_CodeCantBeModified> items = new List<SingleItem_CodeCantBeModified>();
public SingleItemManager()
{
items.Add(new SingleItem_CodeCantBeModified(100));
items.Add(new SingleItem_CodeCantBeModified(200));
}
public void UpdateAllItems()
{
items.ForEach(item => item.Increment());
}
}
提前感谢所有帮助!
答案 0 :(得分:5)
简单的答案是,你做不到。 UpdateAllItems
调用(Increment()
)的方法是非虚拟的,因此您无法模拟它。
我认为你的选择是:
UpdateAllItems
。它的实现是微不足道的,所以这是一个考虑的选择(虽然不是理想的)。SingleItem_CodeCantBeModified
个实例。纯粹主义者会说你现在不再有单位测试了,但它仍然是一个有用的测试。ISingleItem
接口和SingleItemAdapter : ISingleItem
类,该类保留对SingleItem_CodeCantBeModified
的引用并转发呼叫。然后,您可以编写SingleItemManager
来操作ISingleItem
,并且您可以在测试中自由传递模拟ISingleItem
。 (根据系统的设置方式,您甚至可以从SingleItem_CodeCantBeModified
下载,在后代上实现接口,并使用这些对象而不是编写适配器。)最后一个选项为您提供了最多选项,但代价是复杂性。选择最适合您要完成的选项。
答案 1 :(得分:1)
您的经理过于依赖项目(List<Item>
)。你能将列表填充提取到单独的类中以便能够模拟它吗? e.g:
public SingleItemManager()
{
items.Add(ItemRepository.Get(100));
items.Add(ItemRepository.Get(200));
}
测试(省略一些代码):
int i = 0;
var itemMock = new Mock<Item>();
itemMock.Setup(i => i.Increment()).Callback(() => i++);
var repositoryMock = new Moc<ItemRepository>();
repositoryMock.Setup(r => r.Get(It.IsAny<int>()).Returns(itemMock.Object);
var manager = new SingleItemManager();
manager.UpdateAllItems();
Assert.AreEqual(i, 1);
答案 2 :(得分:0)
像往常一样,您可以添加另一个间接级别。
SingleItem_CodeCantBeModified
IItem
interface SingleItemManager
取决于IItem
而不是SingleItem_CodeCantBeModified
OR
如果Increment
是虚拟方法(我知道它不在您的示例代码中,只是以防万一),请使用partial mocking。
答案 3 :(得分:-1)
不要对其他具体项进行硬编码,而是让SingleItem_CodeCantBeModified
实现一个接口(或将其嵌入实现接口的包装器中),然后传入将创建这些项的(新)工厂。
在测试中,您将创建一个模拟工厂以传入您的Manager类,然后您可以监视在该模拟对象上调用的方法。
虽然这更多的是测试系统的内部,而不是副产品。 Manager实现了什么接口?如果它没有在外部证明自己,你会测试什么结果?