【问题标题】:Partial Code Coverage C# - Nunit部分代码覆盖 C# - Nunit
【发布时间】:2013-08-29 20:45:48
【问题描述】:

我有部分代码覆盖,我不知道为什么。 对于那些在开始阅读之前就喜欢这个问题的人

想先说“第一次发帖”,而且我在我的开发生涯中仍然非常初级,但我是一个相对快速的学习者 (imo),所以就这样吧。使用Nunit进行测试,基于MVP。

要测试的代码 -

void _view_Delete(object sender, EventArgs<Guid> e)
    {
        _agRepo.Delete(_agRepo.GetByID(e.Value));

        var g = _agRepo.GetAll();
        if (g.Count() > 0)
        {
            _view.FillRelatableAccessGroups(g.Where(x => x.IsRelatable));//partial coverage
            _view.FillStandAloneAccessGroups(g.Where(x => !x.IsRelatable));//partial coverage
        }

        else
        {
            _view.ShowErrorMsg(true, "No Access Groups Found.");
        }

    }

测试“if”和“else”语句的代码(假设 repo 和 view 被模拟)-

    [Test]
    public void TestDelete()
    {
        _view.Raise(v => v.Delete += null, this, new EventArgs<Guid>(1.ToGuid()));
        _agRepo.AssertWasCalled(r => r.Delete(_agRepo.GetByID(1.ToGuid())));
        _view.AssertWasCalled(v => v.FillRelatableAccessGroups(Arg<IEnumerable<AccessGroup>>.Is.Anything));
        _view.AssertWasCalled(v => v.FillStandAloneAccessGroups(Arg<IEnumerable<AccessGroup>>.Is.Anything));
    }

    [Test]
    public void TestDeleteNoGroups()
    {
        _agList.Clear();
        _view.Raise(v => v.Delete += null, this, new EventArgs<Guid>(1.ToGuid()));
        _agRepo.AssertWasCalled(r => r.Delete(_agRepo.GetByID(1.ToGuid())));
        _view.AssertWasNotCalled(v => v.FillRelatableAccessGroups(Arg<IEnumerable<AccessGroup>>.Is.Anything));
        _view.AssertWasNotCalled(v => v.FillStandAloneAccessGroups(Arg<IEnumerable<AccessGroup>>.Is.Anything));

        _view.AssertWasCalled(x => x.ShowErrorMsg(true, "No Access Groups Found."));
    }

所以我的问题是,我的代码中缺少什么。我需要测试更多的东西,我真的很想找到它。我一直低着头试图完全理解测试的进出。测试驱动开发是我的目标。如果有人有任何类型的输入(好或坏),将不胜感激。我什至不介意有人能把我扔得足够多,这样我就可以开始拉动那根隐喻的弦,它的结尾有我正在寻找的答案。我希望我已经为大家提供了足够的信息。谢谢!

【问题讨论】:

  • nunit 所说的代码的哪一部分没有被您的测试覆盖?
  • 它的 teamcity 声明它没有被覆盖。 Nunit 测试通过。我在上面的代码中有 cmets 表示有问题的代码。
  • 您断言r.Delete() 已被调用。该代码未经过测试。另外,我看不到您在哪里分配数据以从_agRepo.GetAll() 返回。如果您已将其设置为返回零项,则不会评估 x.IsRelatable。您是否已将 nUnit 设置为忽略对简单 get/set 属性的覆盖?
  • 嗯....我想我明白你在说什么。目前无法测试,直到明天。我将看看当我将 GetAll 设置为返回某物然后断言当 g 访问列表时正在调用 isRelatable 时会发生什么?如果我的词汇量没有达到标准,我再次道歉,如果我错误地使用了特定的单词或术语,请随时纠正我。 “你不知道你不知道什么”。另外,不确定 Nunit 是如何配置的。这是一个标准安装并将其作为外部调试器运行。对团队来说还是新手,但我可以确定它是否有助于解决问题。

标签: c# visual-studio-2010 unit-testing nunit code-coverage


【解决方案1】:

_view 被模拟并且 _view 的所有方法都不会对其参数进行操作,例如FillRelatableAccessGroups 将接收它的参数,但不会使用/执行它。

这就是为什么 g.Where(x =&gt; x.IsRelatable)g.Where(x =&gt; !x.IsRelatable) 没有被你的测试覆盖,因为它们永远不会被执行。

如果您需要完整的测试覆盖率,请考虑使用 _view 的正确实现。 类似LINQ: Passing lambda expression as parameter to be executed and returned by method

要记住的一件事是,没有 TDD 原则告诉您实现完整的测试覆盖率。覆盖 90% 以上的最重要地点可能更有价值。

【讨论】:

  • 哇,非常感谢您的完整回复。明天,当我找到正确实施 _view 和测试的方法时,我将看到所涵盖的内容。我个人知道并尊重 90% 的规则。但是,我正在尝试扩展我对单元测试以及自动化测试的理解。还有什么比做更好的理解方式?我喜欢练习和打破,知道问题的原因和方法是接近精通学习环境的唯一途径。期待明天的考试。有哪些方法可以知道哪些代码值得覆盖?
  • 还只是为了澄清您要裁判的 _view 是(我不知道正确的术语)“活动”代码?还是你说的是测试代码?我相信你的意思是活动代码。
  • 太好了,继续破解代码:)。关于_view的问题。如果您有在单元测试中工作的生产代码,请随意使用它。如果生产代码具有您不希望在单元测试中使用的外部依赖项,例如使用任何设备、数据库、文件,那么您必须创建一个测试变体,或修复依赖关系。希望这是有道理的。
  • 我想我明白你想说什么,我不太确定这是否比使用生产代码更容易。在这种情况下,您必须管理您的生产代码以及那些复杂的虚拟实例方法,这将加起来并最终否定模拟框架的好处。但是,如果它对您有用,请使用并看看是否真的会变得很痛苦。
  • 只有当您的生产代码依赖于我在回复中描述为非单元测试的内容时,才会发生长测试。您始终可以选择为代码添加抽象级别,例如通过使用存储库模式。最后你不会有完整的生产代码集,因为你总是要禁止对数据库、文件系统等的调用,但在一定程度上它更容易模拟。
【解决方案2】:

免责声明:我正在尝试正确使用术语,如果我不正确地使用术语,请随时纠正我,我不能强调我对“忘记”我错误吸收的东西的焦虑。我相信我找到了我的解决方案。当前视图不模拟 IEnumerable Where 方法,因为它是一个静态方法。我正在使用 RhinoMocks 并且 RhinoMocks 库不够强大/足够大,无法处理这些系统方法(正确的术语?)。您可以在另一个类中创建一个虚拟实例方法以将静态方法包装在其中,从而使您最终能够模拟 IEnumerable Where 方法。我在这个链接中找到了我的答案:Mocking Static methods using Rhino.Mocks

【讨论】:

    猜你喜欢
    • 2011-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-30
    • 2012-02-23
    • 2023-04-07
    • 2021-04-25
    相关资源
    最近更新 更多