单元测试返回void的方法

时间:2012-12-11 12:51:45

标签: c# unit-testing dependency-injection

想要单元测试以下类中的方法

public class DeviceAuthorisationService : IDeviceAuthorisationService
{
    private DeviceDetailsDTO deviceDetailsDTO = null;
    private IDeviceAuthorisationRepositiory deviceAuthorisationRepositiory;

    public DeviceAuthorisationService(IDeviceAuthorisationRepositioryService paramDeviceAuthorisationRepository)
    {
        deviceAuthorisationRepositiory = paramDeviceAuthorisationRepository;
    }

    public void AuthoriseDeviceProfile(long paramUserID, string paramClientMakeModel)
    {
        if (deviceDetailsDTO == null)
            GetCellPhoneDetails(userID);

        if (deviceDetailsDTO.IsDeviceSelected == false)
            throw new SomeCustomExceptionA();

        if (deviceDetailsDTO.CellPhoneMakeModel.ToLower() != paramClientMakeModel.ToLower())
            throw new SomeCustomExceptionB;
    }

    public void UpdateDeviceStatusToActive(long userID)
    {
        if (deviceDetailsDTO == null)
            throw new InvalidOperationException("UnAuthorised Device Profile Found Exception");

        if (deviceDetailsDTO.PhoneStatus != (short)Status.Active.GetHashCode())
            deviceAuthorisationRepositiory.UpdatePhoneStatusToActive(deviceDetailsDTO.DeviceID);
    }

    private void GetCellPhoneDetails(long userID)
    {
        deviceDetailsDTO = deviceAuthorisationRepositiory.GetSelectedPhoneDetails(userID);

        if (deviceDetailsDTO == null)
            throw new SomeCustomException()
    }

}

注意:

  • Method Name = AuthoriseDeviceProfile返回void
  • 该方法检查userSentMakeModel与存储在db match
  • 中的那个
  • 如果匹配 - 它只返回(即不改变任何状态)

我们如何对这种方法进行单元测试?

  • 嘲笑了Repo
  • 涵盖了“THROWS EXCEPTION”的情景
  • 问题是如何对所有WENT WELL的场景进行单元测试,即用户; s makeModel与存储库匹配; s makeModel

任何有关使这个可测试的设计建议都是最受欢迎的 提前谢谢。

6 个答案:

答案 0 :(得分:15)

由于你的方法返回void,它可能有一些你可以测试/断言的副作用。

在您的情况下,一个选项是提供IDeviceAuthorisationRepositioryService的模拟实例。然后,您可以检查是否发生了对UpdatePhoneStatusToActive的呼叫。以下是使用Moq的解决方案:

var mock = new Mock<IDeviceAuthorisationRepositioryService>();

var service = new DeviceAuthorisationService(mock.Object);
service.UpdateDeviceStatusToActive(....);

mock.Verify(x => service.UpdatePhoneStatusToActive(), Times.Never());

答案 1 :(得分:7)

如果方法无效,那么它应该有一些可观察到的副作用 - 否则它是没有意义的。因此,不测试返回值,而是测试副作用。在这种情况下,看起来可能是在哪些情况下抛出异常。

(这里,“抛出异常”被视为副作用;你当然也可以认为它是一种隐含的返回值......)

答案 2 :(得分:5)

注入模拟的存储库。测试是否调用存储库中的某些方法。

答案 3 :(得分:3)

您可以在单元测试中设置异常预期。在nUnit中它看起来像这样:

[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void TestAuthoriseFail()
{
    // do something that should make the tested method throw the exception
}

答案 4 :(得分:2)

即使你的方法返回void,它也必须做一些对你有用的事情(否则它将是一个毫无意义的方法)。

从你的代码中,我猜测AuthoriseDeviceProfile方法正在做的有两种“有用”的东西:

  • GetSelectedPhoneDetails
  • 上调用IDeviceAuthorisationRepositiory方法
  • 根据特定条件抛出各种例外

因此,要对方法进行单元测试,您应该做两件与此相对应的事情:

  • 注入模拟IDeviceAuthorisationRepositiory并让它记录和/或断言是否调用GetSelectedPhoneDetails
  • 练习测试方法,这些方法会引发各种异常,并在抛出它们时捕获它们以验证:
    • 实际上抛出了一个例外
    • 抛出的异常是适用于每个方案的异常

答案 5 :(得分:0)

d = defaultdict(list)
d['id'] = ['042']
d['success'] = [1, 1, 1]

pd.Series(d)

id             [042]
success    [1, 1, 1]
dtype: object