5

我想测试 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

4 回答 4

5

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

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

看起来您要测试的逻辑在AppendTag. 这是一个静态方法,不会修改任何状态,那么为什么不将其公开并直接由测试调用呢?

同样,您也可以GetParameters通过给它一个附加ArticleInfo参数来使其成为公共静态。

于 2013-11-06T10:38:03.230 回答
3

您可以使内部结构对您的测试项目可见:AssemblyInfo使用InternalsVisibleToAttribute


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

于 2013-11-06T10:23:49.513 回答
2

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

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

例如,请参阅thisthis ,了解为什么不测试实现细节。

更新

我真的不明白为什么人们总是采用这种InternalsVisible方法和其他鼓励测试私有方法的小论点。我并不是说它总是坏的。但大多数时候情况很糟糕。存在一些迫使您测试私有方法的例外情况这一事实并不意味着通常应该建议这样做。所以是的,确实提出了一个解决方案,使测试实现细节成为可能,但是在你描述了一般来说什么是有效的方法之后。关于这个问题有大量的博客文章和 SO 问题,为什么我们必须一遍又一遍地经历这个?(反问)。

于 2013-11-06T10:24:28.330 回答
0

在您的 properties/assemblyinfo.cs 添加:

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

编辑 有些人喜欢测试内部和私有方法,而其他人则不喜欢。我个人更喜欢它,因此我使用 InternalsVisibleTo。但是,内部是内部的,因此应谨慎使用。

于 2013-11-06T10:25:50.837 回答