单元测试与私有集合相关的公共方法

时间:2015-04-09 08:44:07

标签: c# unit-testing nunit

我的班级有一个私人懒惰字典和一些与之交互的方法

public class MyClass : IExampleClass
{
    private Lazy<Dictionary<string, IMyObject>> myObjects = new Lazy<Dictionary<string, IMyObject>>();
    private Dictionary<string, IMyObject> MyObjects
    {
        get
        {
            return myObjects.Value;
        }
    }

    public class MyClass()
    {}

    public void RegisterObject(string name, IMyObject object)
    {
        logger.LogInfo("Executed RegisterObject etc.");

        if (String.IsNullOrEmpty(name) == false && object != null && MyObjects.ContainsKey(name) == false)
        {
             MyObjects.Add(name, object);
        }
        else
        {
             logger.LogWarning("Cannot register the object because etc.");
        }
    }

    public IMyObject GetObject(string name)
    {
        logger.LogInfo("Executed GetObject etc.");

        IMyObject obj = null;
        if (String.IsNullOrEmpty(name) == false)
        {
            Objects.TryGetValue(name, out obj);
        }

        return obj;
    }
}

这是有用的,因为有时会发生一些插入的对象为空,所以我会防止任何进一步的损害,避免添加它们。 现在我在测试阶段遇到了一个问题(我知道,在测试之前我会感到羞耻,我在测试前编写代码),因为我被迫在同一个测试中使用这两种方法:

[TestFixture]
public class MyClassTest 
{
    [Test]
    public void RegisterObject_WithNullNameAndNullObject_DoNothing()
    {
        //Arrange
        string inputName = null;
        IMyObject inputObject = null;
        IExampleClass sut = new MyClass();

        //Act
        sut.RegisterObject(inputName, inputObject);

        //Assert
        IMyObject actualValue = sut.GetObject(inputName);
        Assert.IsNull(actualValue);
    }

    ...
}

最重要的是,我如何处理我试图在字典中插入元素的测试?

    [Test]
    public void RegisterObject_AlreadyInserted_DoNothing()
    {
        //Arrange
        string inputName = "test";
        IMyObject inputObject = A.Dummy<IMyObject>();
        IExampleClass sut = new MyClass();

        // ??? 
        sut.RegisterObject(inputName, inputObject);
        // how can i effectively test the method if i'm using it more than once???

        //Act
        sut.RegisterObject(inputName, inputObject);

        //Assert
        IMyObject actualValue = sut.GetObject(inputName);

        // ???
        Assert.AreEqual(inputObject, actualValue);
        // What i've tested here? The fact that the dictionary contains
        // the object doesn't mean that the second call of RegisterObject
        // is ignored.
    }

所以最后我问:

  1. 测试RegisterObject里面调用GetObject是否正确?
  2. 如果必须测试第二次插入被忽略,我如何安排字典呢?
  3. 另一方面,我有7个独立的RegisterObject测试:

    • RegisterObject_WithNullNameAndNullObject_DoNothing()
    • RegisterObject_WithNullNameAndValidObject_DoNothing()
    • RegisterObject_WithEmptyNameAndNullObject_DoNothing()
    • RegisterObject_WithEmptyNameAndValidObject_DoNothing()
    • RegisterObject_WithValidNameAndNullObject_DoNothing()
    • RegisterObject_WithValidNameAndValidObject_RegisterObject()
    • RegisterObject_AlreadyInserted_DoNothing()

    这有点矫枉过正?这种简单行为的测试太多了?

1 个答案:

答案 0 :(得分:0)

  

测试RegisterObject里面调用GetObject是否正确?

鉴于我们所知道的MyClass的公共界面是RegisterObjectGetObject,我认为您还无法做其他事情。 即使你可以做别的事,我也不会。您希望确保该类以某种方式为其使用者行事,因此像消费者一样使用它。这就是你如何判断它是否正在发挥作用。

  

如果我必须测试忽略第二次插入,我如何安排字典?

从消费者的角度考虑这个问题。你想要发生什么?您似乎想要表明,如果您在现有密钥下插入第二个对象,该方法将静默成功,但是存储的值是原始值。我们怎么知道存储了什么?致电GetObject。所以我认为你的测试很好,但我会使用不同的值来插入。这样你可以判断是否有任何改变。如果GetObject返回原始值,那么您的方法就是正确的。