C# 在C语言中测试两个依赖类#
我想解决的问题是,如何在C#中测试两个依赖类。对于测试,我使用NUnit和Moq 假设我有一个自定义集合,可以自动计算其项目。集合中的值必须保持其原始顺序,这就是它必须自动计算的原因。以下代码显示了上述类的最简单示例:C# 在C语言中测试两个依赖类#,c#,unit-testing,dependencies,moq,C#,Unit Testing,Dependencies,Moq,我想解决的问题是,如何在C#中测试两个依赖类。对于测试,我使用NUnit和Moq 假设我有一个自定义集合,可以自动计算其项目。集合中的值必须保持其原始顺序,这就是它必须自动计算的原因。以下代码显示了上述类的最简单示例: public interface ICustomItem { int Id { get; set; } ICustomCollection<ICustomItem> ParentCollection { get; set; } } public in
public interface ICustomItem
{
int Id { get; set; }
ICustomCollection<ICustomItem> ParentCollection { get; set; }
}
public interface ICustomCollection<T> where T : ICustomItem
{
IEnumerable<T> Items { get; set; }
void Add(T t);
// And more of course...
}
public class CustomCollection<T> : ICustomCollection<T> where T : ICustomItem
{
public IEnumerable<T> Items { get; set; }
public void Add(T t)
{
// Some logic here...
t.Id = Items.Count(); // Generate Id
}
}
公共接口ICustomItem
{
int Id{get;set;}
ICustomCollection ParentCollection{get;set;}
}
公共接口ICustomCollection,其中T:ICustomItem
{
IEnumerable Items{get;set;}
无效添加(T);
//当然还有更多。。。
}
公共类CustomCollection:ICustomCollection,其中T:ICustomItem
{
公共IEnumerable项{get;set;}
公共无效添加(T)
{
//这里有些逻辑。。。
t、 Id=Items.Count();//生成Id
}
}
将项目添加到集合时,将生成一个新Id并将其分配给CustomItem。自动计算机制也应该包括在其他方法中,例如Remove(),但对于这个问题,我只留下Add方法
问题是,如何测试自动编码是否正确工作?当mock作为param传递时,它不会在类内部修改。我是否应该使用为tests CustomItem类创建的简单实例测试该类
tl;dr
换句话说,我希望能够在类中修改mock。事实上,mock没有被修改。但是,您应该能够在调用add方法后验证模拟,如下所示:
mock.VerifySet(x => x.Id = 42);
在调用Add之前,请记住在Items属性中设置一些内容。当询问Count()时,某物应该返回42。这也可能是一个模拟。尝试在测试中使用该类,就像在生产代码中使用它一样。这将为您提供最有用的测试,因为您可以自由重构类内部的代码,而无需中断甚至更改测试。该测试还将作为如何使用该类的示例 首先,我不会使用Moq,而是使用一个简短的
MockCustomItem
类,您只为测试而实现它
然后使用add一些值并断言结果是您所期望的。养成在每个测试中只使用一个断言的习惯,如下所示
[TestFixture]
public class GivenCustomCollectionWithTwoElements
{
private CustomCollection<MockCustomItem> _customCollection;
[SetUp]
public void SetUp()
{
_customCollection = new CustomCollection<MockCustomItem>();
_customCollection.Add(new MockCustomItem());
_customCollection.Add(new MockCustomItem());
}
[Test]
public void CheckLength()
{
Assert.That(_customCollection.Items, Is.EqualTo(2));
}
[Test]
public void CheckFirstItemId()
{
Assert.That(_customCollection.Items.ElementAt(0).Id, Is.EqualTo(0));
}
[Test]
public void CheckSecondItemId()
{
Assert.That(_customCollection.Items.ElementAt(1).Id, Is.EqualTo(1));
}
private class MockCustomItem : ICustomItem
{
public int Id { get; set; }
public ICustomCollection<ICustomItem> ParentCollection { get; set; }
}
}
[TestFixture]
具有两个元素的public类givencustomcollection
{
私人CustomCollection\u CustomCollection;
[设置]
公共作废设置()
{
_customCollection=新建customCollection();
_添加(新MockCustomItem());
_添加(新MockCustomItem());
}
[测试]
公共void CheckLength()
{
断言(_customCollection.Items,Is.EqualTo(2));
}
[测试]
public void CheckFirstItemId()
{
Assert.That(_customCollection.Items.ElementAt(0.Id,Is.EqualTo(0));
}
[测试]
public void CheckSecondItemId()
{
Assert.That(_customCollection.Items.ElementAt(1.Id,Is.EqualTo(1));
}
私有类MockCustomItem:ICustomItem
{
公共int Id{get;set;}
公共ICustomCollection父集合{get;set;}
}
}
一旦掌握了窍门,还可以使用Moq创建更简洁的测试,使用更少的样板代码。在这种情况下,也可以使用NUnit参数化测试用例。在单元测试中,您只能测试当前正在测试的单元。所以我想说,你应该模拟/伪造ICustomItem并发送它,然后查看伪造的对象是否获得了你期望的Id 请阅读我的答案,了解关于同一主题的更多信息 我使用FakeiTesy作为模拟/伪框架,但我想moq看起来很相似,下面是我的代码
[TestFixture]
public class CustomCollectionTests{
[Test]
public void Add_AddTwoItems_ItemsGetsConsecutiveIds() {
var customItem1 = A.Fake<ICustomItem>();
var customItem2 = A.Fake<ICustomItem>();
var cutomCollection = new CustomCollection<ICustomItem>();
cutomCollection.Add(customItem1);
cutomCollection.Add(customItem2);
Assert.AreEqual(1, customItem1.Id);
Assert.AreEqual(2, customItem2.Id);
}
}
public interface ICustomItem {
int Id { get; set; }
}
public interface ICustomCollection<T> where T : ICustomItem {
void Add(T t);
}
public class CustomCollection<T> : ICustomCollection<T> where T : ICustomItem {
public List<T> innerList = new List<T>();
public void Add(T t) {
// Some logic here...
innerList.Add(t);
t.Id = innerList.Count(); // Generate Id
}
}
[TestFixture]
公共类CustomCollectionTests{
[测试]
public void Add_addtwooitems_ItemsGetsConsecutiveIds(){
var customItem1=A.Fake();
var customItem2=A.Fake();
var cutomCollection=new CustomCollection();
添加(customItem1);
cutomCollection.Add(customItem2);
aresequal(1,customItem1.Id);
aresequal(2,customItem2.Id);
}
}
公共接口ICustomItem{
int Id{get;set;}
}
公共接口ICustomCollection,其中T:ICustomItem{
无效添加(T);
}
公共类CustomCollection:ICustomCollection,其中T:ICustomItem{
public List innerList=新列表();
公共无效添加(T){
//这里有些逻辑。。。
innerList.Add(t);
t、 Id=innerList.Count();//生成Id
}
}
编辑
删除了似乎不起作用的未测试MOQ示例。为什么不能使用模拟?您可以使用Id属性上的SetupSet创建mock。@msergey:但是如何设置mock Id setter来检查它是否在Add()方法中被正确修改?你能提供一个例子吗?你能在Add()之后检查它吗?因此,您将项添加到集合中,并在运行add之后检查Id设置是否正确。您的Moq代码是错误的:首先,您必须使用customItem#.Object,其次,您不能修改一个mock inside add()方法。啊,Fakeitesy似乎可以更轻松地处理此问题;)我再次删除了MOQ代码示例。请查看此链接,其中Osherove解释了为什么每个测试一个断言很重要:我可能会将Id的生成移动到另一个类,而不是将其包含在集合中。如果你阅读单一责任原则,你会发现一个班级应该有一个责任。你的收藏既储存了ICustomItems,又对它们进行了修改。哇,我刚刚注意到维斯蒂奇和文特1是两个不同的人;)我以为我一直在和同一个人说话。。。我的错。对不起;)我所说的一切仍然适用,尽管很抱歉。刚刚意识到您正在IEnumerable上使用Count()扩展方法,而不是List和其他集合类型上可用的Count属性。Count()是一个s