你会如何测试它?多少次测试?

时间:2013-04-19 21:20:35

标签: c# unit-testing

我有这个类(它更伪代码)


public class Roles
{
    private ProcessData processData;

    Roles(ProcessData pd)
    {
        processData = pd;
    }

    public string[] GetLoginsThatCanCallAction(string actionName)
    {
        return GetPeopleThatCanCallActionFromDb(actionName)
            .Union(processData.ProcessOwner)
            .Union(GetFromDb(Role.Administrators);
            // there may be many more Union(xyz) calls here
            .ToArray();
    }

    // I can refactor those methods to be mockable
    private GetPeopleThatCanCallActionFromDb(...)
    private GetFromDb(...)
}

现在我的问题是。你会在GetLoginsThaatCanRunAction方法中为每个Union调用编写一个测试吗? 或者只是我写了一个测试并断言该方法返回从GetLoginsThatCanCallAction内部调用的所有方法返回的登录。

我可以看到两种方式做到这一点的理由。但也许有人会说服我或其他解决方案。

编辑: 我想我不清楚我的问题:我想问你是否会写这个测试


var pd = new ProcessData()
pd.ProcessOwner = "Owner";
var r = new Roles(processData)
SetupSoThatCallsForPeopleThatCanCallActionWillReturn("Joe");
SetupSoThatCallForAdministratorsWillReturn("Administrator");

var logins = r.GetLoginsThatCanCallAction("some action");

Assert.That(logins, Contains("Owner");
Assert.That(logins, Contains("Joe");
Assert.That(logins, Contains("Administrator");

或者你会将它分成3个单独的测试,每个测试中有一个Assert?

3 个答案:

答案 0 :(得分:2)

有趣的话题,您的问题是您在开发了一些代码后尝试编写测试用例。我会为每个联盟电话进行1次测试。原因是你想测试你从所有方法返回的值或者你想在不同的假设下测试它EACH方法将返回一个登录?

对我而言,更重要的是知道每个方法将返回基于不同用例的登录,而不是将返回通过/失败的通用测试。

我希望这是有道理的。

答案 1 :(得分:2)

我会为GetLoginsThatCanCallAction模拟外部对象编写一个测试。从您的示例中,这可能意味着模拟Union调用。原因是,当我编写这段代码时,我并不关心Union中使用的逻辑。 (我有过甚至还没写过的情况)。

如果联合调用行为可以改变,(IE它会抛出异常),我会对每个进行测试。但是,我会让我的测试套件为我生成这些测试用例,而不是试图手动编写它们。

您担心GetLoginsThatCanCallAction行为正确。您还希望控制Union调用返回的内容。

话虽如此,您还希望进行自动化测试,以执行GetLoginsThatCanCallAction使用的整个过程,以便验证您在单元测试中模拟的类之间的连接。除非您无法亲自手动执行该过程。

另一个注意事项,如果课程很难测试。这是一种代码味道,你的设计并不像它那样模块化。

如果你需要这样做来测试函数,我也会避免模拟类的内部方法。这表明你的班级里面隐藏着另一个班级。你的班级做了不止一件事the S in SOLID

答案 2 :(得分:1)

您应该只运行被测单位的公共API。您的单位有单一的公共方法GetLoginsThatCanCallAction。此方法是否调用其他方法或实现为一个大方法无关紧要。这是一个实现细节。真正重要的是此方法是否与依赖项正确通信并返回预期结果:

// Arrange
Mock<IProcessData> processData = new Mock<IProcessData>();
processData.Setup(d => d.ProcessOwner).Returns(new[] { "Bob" });
var expected = new []{ "Bob", "Joe" };
// Act
var actual = roles.GetLoginsThatCanCallAction("Drink");
// Assert
processData.VerifyGet(d => d.ProcessOwner); // verify communication
CollectionAssert.AreEquivalent(expected, actual); // verify result