我应该如何测试访问私有成员的公共方法

时间:2011-06-03 12:37:54

标签: c# nunit

所以我有一些与此相关的内容

private List<ConcurrentQueue<int>> listOfQueues = new List<ConcurrentQueue<int>>()
public void InsertInt(int id, int value)
{
    listOfQueues[id].Enqueue(value);
}

这是我不应该进行单元测试吗? 如果是如何在不使用任何其他方法的情况下测试InsertInt方法? 是否可以使用该方法从队列中检索数据以测试它是否正确输入? 这是我应该使用模拟的东西吗?

6 个答案:

答案 0 :(得分:2)

是的,你应该进行单元测试。您可以使用私有访问器来获取listOfQueues。 您必须确保使用单元测试,该方法的行为符合预期,但异常并且项目确实已插入。

查看这篇文章,了解如何对私有方法进行单元测试http://msdn.microsoft.com/en-us/library/ms184807(v=vs.80).aspx

答案 1 :(得分:2)

您通常不想测试私人会员。单元测试的重点是从外部开始,类采用指定的输入,并且(在请求时)将为您提供正确的输出。你不关心如何实现它给你那些输出,你只关心它为你提供正确的外部输出输出。

要显示此信息,请假设您创建了一个单元测试,以验证您的InsertInt()方法是否将int插入listOfQueues。然后,您的需求会发生变化,您必须更改实施策略,而不是使用List<ConcurrentQueue<int>>,而是变为Dictionary<string, ConcurrentQueue<int>>。这可能实际上并不需要更改您的输入,并且您的输出仍然可以通过任何输出验证,但您的InsertInt()单元测试将失败,因为它被硬编码为实现。

更好的想法是进行单元测试,确保如果使用正确的输入调用InsertInt(),输出方法仍将返回更正的输出,以及创建调用{{1}的单元测试带有无效参数会导致异常。然后,您可以更改有关内部实施的所有内容,并确信您的课程仍在正常运行。单元测试实现增加了额外的开销,同时在可测试性方面提供的好处很少。

请注意,我并不是说这种方法不应该进行单元测试,只是单元测试需要以反映外部对象如何与您的类进行交互的方式开发。

答案 2 :(得分:1)

由于此方法是公共方法,因此需要进行单元测试。

快速查看您的方法会发现,将-1作为id的值传递会导致ArgumentOutOfRangeException。如果已经设计了这种方法的单元测试用例(假设存在许多这样的方法),那么在编码期间就可以实现这一点。

要检查插入是否成功,您可以使用@Oskar Kjellin指出的方法。

如果你想弄脏,那么你可以使用Reflection来检查是否插入了值。

// Sample with Queue instead of ConcurrentQueue
private void TestInsertInt(int id, int value)
{
    myInstance.InsertInt(id, value);

    FieldInfo field = myInstance.GetType().GetField("listOfQueues", BindingFlags.NonPublic | BindingFlags.Instance);
    List<Queue<int>> listOfQueues = field.GetValue(myInstance) as List<Queue<int>>;
    int lastInserted = listOfQueues[id].Last();

    Assert.AreEqual(lastInserted, value);
}

答案 3 :(得分:1)

您不应该测试队列的行为 - 这是一个可以在不改变方法行为的情况下更改的实现细节。例如,您可以将ConcurrentQueue替换为另一个数据结构(可能是树),而无需更新单元测试。

您正在测试的是此方法接受输入并按预期存储值。因此,您需要某种方式来询问系统的状态,例如

public int GetInt(int id)

然后,通过使用相同的id检索方法,测试该方法是否按预期插入。

您应该测试公共方法在您能想到的每种情况下都返回您期望的结果,并将其留给方法来存储它认为合适的值。因此,我可能会使用不同的输入测试这样的方法:

        [TestCase(1,2,3)] // whatever test cases make sense for you
        [TestCase(4,5,6)]
        [TestCase(7,8,9)]
        [Test]
        public void Test_InsertInt_OK( int testId, int testValue, int expectedValue)
        {
            InsertInt(testId, testValue);
            Assert.AreEqual( GetInt(testId), expectedValue )
        }

答案 4 :(得分:0)

  

这是我不应该成为单位的东西吗?   测试

如果您的目标是100%测试覆盖率,那么是

  

如果是我如何测试InsertInt   没有使用任何其他方法   方法

有几个选择:

  • 使用不同的访问者方法 你建议。
  • 使容器内部并让单元测试组件访问内部
  • 将容器分解为一个单独的类,您将该类作为依赖项传递给此类,然后在单元测试中传递一个模拟容器
  • 使用反射来访问私人会员

答案 5 :(得分:0)

另一个黑客是使用PrivateObject

就个人测试而言,我个人会使用DI(依赖注入)或制作privateinternal