1

I have this class (it's more pseudocode)


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(...)
}

Now my question is. Would you write one test for each Union call in GetLoginsThaatCanRunAction method? Or is is just enough that I write one test and assert that method returns logins returned from all methods called inside GetLoginsThatCanCallAction.

I can see reasons to do it both ways. But maybe someone will convince me to on or the other solution.

Edit: I think I wasn't clear with my question: I wanted to ask if you would write this test


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");

or would you split it into 3 separate tests with one Assert in each one?

4

3 回答 3

2

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

对我来说,更重要的是知道每种方法都会根据不同的用例返回登录信息,而不是通用测试返回我通过/失败。

我希望这是有道理的。

于 2013-04-19T21:38:25.653 回答
2

我会写一个测试来GetLoginsThatCanCallAction模拟外部对象。从您的示例来看,这可能意味着嘲笑Union电话。原因是,当我编写这段代码时,我并不关心Union. (我有一些我什至还没有写的案例)。

如果联合调用行为可以改变(即它引发异常),我将对其中的每一个进行测试。但是,我会让我的测试套件为我生成这些测试用例,而不是尝试手动编写它们。

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

话虽如此,您还希望有一个自动化测试来执行整个过程,GetLoginsThatCanCallAction以便您在单元测试中验证您正在模拟的类之间的连接。除非不可能自己手动执行该过程。

另一个注意事项,如果课程很难测试。那是一种代码味道,表明您的设计没有达到应有的模块化程度。

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

于 2013-04-19T21:40:22.570 回答
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
于 2013-04-19T21:38:24.490 回答