单元测试c#并测试私有方法

时间:2013-11-06 10:20:42

标签: c# .net unit-testing moq

我想测试GetParameters()断言返回的值包含值中的“test =”。不幸的是,负责这个的方法是私有的。有没有办法为此提供测试覆盖?我遇到的问题如下所示:

if (info.TagGroups != null)

问题是我的测试中的info.TagGroups等于null

谢谢,

测试

[Test]
public void TestGetParameters()
{
    var sb = new StringBuilder();
    _renderer.GetParameters(sb);
    var res = sb.ToString();
    Assert.IsTrue(res.IndexOf("test=") > -1, "blabla");
}   

要测试的实施类

internal void GetParameters(StringBuilder sb)
{
    if (_dPos.ArticleInfo != null)
    {
        var info = _dPos.ArticleInfo;

        AppendTag(sb, info);

    }
}

private static void AppendTag(StringBuilder sb, ArticleInfo info)
{
    if (info.TagGroups != null)  // PROBLEM - TagGroups in test equals null
    {
        foreach (var tGroups in info.TagGroups)
        {
            foreach (var id in tGroups.ArticleTagIds)
            {
                sb.AppendFormat("test={0};", id);
            }
        }
    }
}

4 个答案:

答案 0 :(得分:5)

直接测试私有方法 (而不是通过类的公共API间接测试)通常是一个坏主意。但是,如果需要,可以通过反射来实现。

更好的选择是重构代码以使其更易于测试。有很多方法可以做到这一点,这里有一个选项:

您想要测试的逻辑看起来像AppendTag。这是一个静态方法,并且不会修改任何状态,那么为什么不直接通过测试使其公开和可调用?

同样,您也可以通过为其添加GetParameters参数来使ArticleInfo公共静态。

答案 1 :(得分:3)

您可以在测试项目中看到内部:AssemblyInfo使用InternalsVisibleToAttribute

<小时/> 免责声明:
测试私有/内部方法很糟糕!它不是TDD,在大多数情况下,这是停止和重新思考设计的标志。
但是如果您被迫这样做(应该测试的遗留代码) - 您可以使用这种方法。

答案 2 :(得分:2)

是的,您只需将_dPos.ArticleInfo的适当内容注入您的班级即可。这样,您可以确保私有方法中将涵盖所有路径。另一种可能性是使用TDD重写这个简单的代码 - 这将为您提供近100%的覆盖率。

另请注意,通常您不应该关心私有方法的工作原理。只要你的班级正确地暴露了所需的行为,一切都很好。在测试期间过多考虑内部因素会使您的测试与实施细节相结合,这会使测试变得脆弱且难以维护。

请参阅thisthis,了解为何不测试实施细节。

<强>更新

我真的不明白为什么人们总是采用InternalsVisible方法和鼓励测试私有方法的其他小论点。我不是说它总是坏的。 但大部分时间都不好。存在一些迫使您测试私有方法的特殊情况这一事实并不意味着一般应该建议这样做。所以,是的,确实提供了一个解决方案,使测试实现细节成为可能,后,您已经描述了一般的有效方法。在这个问题上有大量的博客文章和SO问题,为什么我们必须一遍又一遍地经历这个问题? (修辞问题)。

答案 3 :(得分:0)

在您的properties / assemblyinfo.cs中添加:

  [assembly: InternalsVisibleTo("**Insert your test project here**")]

修改 有些人喜欢测试内部和私人方法,有些人则不喜欢。我个人更喜欢它,因此我使用InternalsVisibleTo。但是,内部结构是内部的,因此应谨慎使用。