在C#中测试两个依赖类

时间:2011-07-15 08:30:50

标签: c# unit-testing dependencies moq

我想解决的问题是,如何在C#中测试两个依赖类。为了测试我正在使用NUnit和Moq。

假设我有一个自定义集合,它自动枚举其项目。集合中的值必须保持原始顺序,这就是为什么必须自动枚举的原因。以下代码显示了上述类的最简单示例:

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
    }
}

将项目添加到集合时,会生成新的Id并将其分配给CustomItem。 autonumerating的机制也应该包含在其他方法中,例如Remove(),但对于这个问题,我只留下了Add方法。

问题是,如何测试autonumerates是否正常工作?当mock作为param传递时,它不会在类中修改。我应该使用create-for-tests CustomItem类的简单实例测试该类吗?

TL;博士

换句话说,我希望能够在类中修改模拟。

3 个答案:

答案 0 :(得分:1)

尝试在测试中使用该类,就像在生产代码中使用它一样。这将为您提供最有用的测试,因为您可以自由地重构类中的代码,而不会破坏甚至更改测试。该测试还将作为如何使用该类的示例。

首先,我不会使用Moq,而是使用您仅为测试实现的简短MockCustomItem类。

然后使用添加一些值并断言结果是您所期望的。养成在每个测试中仅使用一个断言的习惯,如下所示。

[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; }
    }

}

一旦掌握了这一点,您还可以使用Moq以更少的样板代码创建更简洁的测试。在这种情况下,也可以使用NUnit参数化测试用例。

答案 1 :(得分:1)

在单元测试中,您只能测试您正在测试的单元。所以我说你应该模拟/伪造ICustomItem然后发送它,然后查看伪造的对象是否得到你期望的Id。

请阅读我的回答,了解有关同一主题Any ASP.NET (WebForm) apps which have good unit tests (CodePlex or anywhere)?

的更多信息

我使用FakeItEasy作为模拟/假框架,但我想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
    }
}

修改

删除了未经测试的MOQ示例,该示例似乎无效。

答案 2 :(得分:0)

你是对的,因为模拟没有被修改。但是你应该能够在调用add方法之后验证mock,如下所示:

mock.VerifySet(x => x.Id = 42);

请记住在调用Add之前在Items属性中设置一些内容。当要求Count()时,那个东西应该返回42。这也可能是模拟。