C# 如何使用Moq测试没有返回值的方法?
这是我的第一个问题,所以请客气点!:) 我试图做的是为一个manager类编写一些测试,该类在构建过程中会向列表中添加单个item类的许多新实例。当在这个管理器类中调用UpdateAllItems时,目的是迭代列表并对每个项目调用增量 manager类是我的代码,但single item类不是,因此我无法修改它 我使用NUnit作为测试框架,并开始使用Moq。因为manager类使用了singleitem类,所以我认为我需要使用Moq,所以我只测试manager,而不是singleitem 如何为UpdateAllItems方法编写测试?(从技术上讲,我应该先编写测试) 下面是一些示例代码,它给出了我正在使用的东西的一般概念C# 如何使用Moq测试没有返回值的方法?,c#,.net,unit-testing,mocking,moq,C#,.net,Unit Testing,Mocking,Moq,这是我的第一个问题,所以请客气点!:) 我试图做的是为一个manager类编写一些测试,该类在构建过程中会向列表中添加单个item类的许多新实例。当在这个管理器类中调用UpdateAllItems时,目的是迭代列表并对每个项目调用增量 manager类是我的代码,但single item类不是,因此我无法修改它 我使用NUnit作为测试框架,并开始使用Moq。因为manager类使用了singleitem类,所以我认为我需要使用Moq,所以我只测试manager,而不是singleitem 如何
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());
}
}
public类SingleItem\u CodeCantBeModified
{
public int CurrentValue{get;private set;}
公共单项_CodeCantBeModified(int起始值)
{
CurrentValue=起始值;
}
公共空间增量()
{
CurrentValue++;
}
}
公共类SingleItemManager
{
列表项=新列表();
公共单项目管理器()
{
添加(新的单一项_CodeCantBeModified(100));
添加(新的单一项_CodeCantBeModified(200));
}
public void UpdateAllItems()
{
items.ForEach(item=>item.Increment());
}
}
提前感谢所有的帮助 您的经理过于依赖项目(在
列表中)。您能将列表填充提取到单独的类中以模拟它吗?e、 g:
public SingleItemManager()
{
items.Add(ItemRepository.Get(100));
items.Add(ItemRepository.Get(200));
}
测试(部分代码省略):
inti=0;
var itemMock=new Mock();
Setup(i=>i.Increment()).Callback(()=>i++);
var repositoryMock=new Moc();
Setup(r=>r.Get(It.IsAny()).Returns(itemMock.Object);
var manager=新的SingleItemManager();
manager.UpdateAllItems();
断言.AreEqual(i,1);
不要硬编码额外的具体项目,而是让SingleItem\u CodeCantBeModified
实现一个接口(或将其嵌入实现接口的包装器中),然后传入一个(新的)工厂,该工厂将创建这些项目
在您的测试中,您将创建一个工厂的模拟以传递给Manager类,然后您可以监视在该模拟对象上调用了哪些方法
虽然这更多的是测试系统的内部,而不是副产品。管理器实现的是什么接口?如果它没有在外部证明自己,您测试的结果是什么?像往常一样,您可以添加另一个间接级别
围绕SingleItem\u CodeCantBeModified
使此包装器继承IItem
接口
使SingleItemManager
依赖IItem
而不是SingleItem\u CodeCantBeModified
或
如果Increment
是一个虚拟方法(我知道它不在示例代码中,只是以防万一),请使用。简单的答案是,你不能。updatealItems
调用的方法(Increment()
)是非虚拟的,因此你无法模拟它
在我看来,你的选择是:
完全不要测试<代码> UpDATEALLATION< /COD>。它的实现是微不足道的,所以这是一个需要考虑的选项(虽然不理想)。
- 在测试中创建真正的
SingleItem\u CodeCantBeModified
实例。纯粹主义者会说,此时您不再有单元测试,但它仍然可能是一个有用的测试
- 添加一个
ISingleItem
接口和一个ISingleItemAdapter:ISingleItem
类,该类保留对SingleItem\u CodeCantBeModified
的引用并转发调用。然后,您可以编写SingleItemManager
对ISingleItem
进行操作,并且可以自由地传递模拟ISingleItem代码>测试中的。(取决于系统的设置方式,您甚至可以从SingleItem\u CodeCantBeModified
,在后代上实现接口,并使用这些对象而不是编写适配器。)
最后一个选项为您提供了最多的选项,但要付出一定的复杂性。请选择最适合您尝试完成的任务的选项。SingleItem\uCodeCantBeModified@riezebosch:如果push出现问题,您可以创建一个代理对象来实现interfacet,并且只通过方法调用这与获取类来实现接口一样,但具有相同的效果。这个类有何用处?它创建计数器的私有列表,并在每次调用方法时更新每个项。对象的行为必须有一些更改。例如,如果UpdateAllItems不起作用-观察到的更改是什么?
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);