Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
单元测试c#和测试私有方法的问题_C#_.net_Unit Testing_Moq - Fatal编程技术网

单元测试c#和测试私有方法的问题

单元测试c#和测试私有方法的问题,c#,.net,unit-testing,moq,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

我想测试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);
            }
        }
    }
}
要测试的实现类

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

您可以使内部构件对测试项目可见:在
AssemblyInfo
use中。
免责声明:

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

是的,您只需要将
\u dPos.ArticleInfo
的适当内容注入到您的类中。通过这种方式,您可以确保私有方法将覆盖所有路径。另一种可能是使用重写这个简单的代码-这将为您提供几乎100%的覆盖率

还要注意,一般来说,您不应该真正关心私有方法是如何工作的。只要您的类正确地公开所需的行为,一切都很好。在测试过程中过多地考虑内部因素会使您的测试与实现的细节结合在一起,这会使测试变得脆弱且难以维护

请参阅和,例如,关于为什么不测试实现细节

更新


我真的不明白为什么人们总是使用
InternalsVisible
方法和其他鼓励测试私有方法的小论点。我不是说它总是坏的但大多数时候都很糟糕。事实上,存在一些迫使您测试私有方法的例外情况并不意味着一般情况下应该建议这样做。因此,是的,一定要提出一个解决方案,使测试实现细节成为可能,但在之后,您已经描述了一般有效的方法。关于这件事,有很多博客帖子和问题,为什么我们要一遍又一遍地讨论这个问题?(反问)。

在您的属性/assemblyinfo.cs中添加:

  [assembly: InternalsVisibleTo("**Insert your test project here**")]
编辑
有些人喜欢测试内部和私有方法,而有些人不喜欢。我个人更喜欢它,因此我使用InternalsVisibleTo。但是,内部构件是内部构件,这是有原因的,因此应谨慎使用

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

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

您要测试的逻辑似乎位于
AppendTag
中。这是一个静态方法,不修改任何状态,所以为什么不将其公开并直接由测试调用呢


同样,您也可以通过为
GetParameters
提供一个额外的
ArticleInfo
参数,使其成为公共静态。

测试私有方法是一种不好的做法,会导致脆弱和不可维护的测试。我已将这一行添加到我的测试类中。这是如何改变我的测试的?@StijndeVoogd我已经给了你一个明确的例子,为什么这是错误的。耦合过多会导致问题。@JamesRadford您应该将此行添加到AssemblyInfo.cs文件中。您可以在“项目/属性”文件夹中找到它。请确保将其与内部方法放在同一个项目中。@StijndeVoogd lol,对不起,耦合是否增加并不是意见问题。是的,因为您将测试与实现细节联系在一起。因此,您不再能够在不改变行为的情况下自由地更改实现,而不必一次又一次地修复测试。这破坏了封装。只要公共接口公开正确的行为,实现细节就不重要了。请参考我在回答中给出的一些示例链接。没有人会确切地告诉您如何使
标记组
非空-如何猜测
ArticleInfo
的实现?如果您不能轻松地注入值以确保它不是
null
,则表示您的类不可测试。在这种情况下,我再次推荐TDD方法(见我的答案)。每次有人询问如何测试私有方法(圣战开始)。在现实生活中,有些遗留系统无法承受太多重构。詹姆斯问如何处理这个问题,答案是反思。@nikita是的,我们都知道“现实生活”和“遗产”。但在这种情况下,遗留代码没有任何内容。总的来说,改进设计是答案。反射仅适用于遗留代码,或者当您真的没有其他选择时。我不知道为什么这个特殊的解决方案总的来说一直被认为是一个好的解决方案,但只有这一个特殊的论点支持它。