问题 如何断言是否使用nunit调用了一个方法


是否可以断言是否已调用方法?我正在测试以下方法,我想声明_tokenManager.GetToken()已被调用。我只是想知道方法是否已被调用,因为该方法不返回值。我正在使用Moq。

谢谢,

代码段

public void Subscribe(string code, string emailAddress, string columnKey)
{
    // Request authentication token
    var token = _tokenManager.GetToken(code, false);

    if (!_tokenValidator.Validate(token))
    {
        // Token has expired or invalid - refresh the token 
        token = _tokenManager.GetToken(code, true);
    }

    // Subscribe email
    _silverpopRepository.Subscribe(token.AccessToken, emailAddress, columnKey);
}

912
2017-12-02 15:33


起源

您是否看过MOQ或其他模拟框架?我相信NUnit有自己的,但我不熟悉它? - Justin Pihony
我已经更新了我的问题,我正在使用Moq。 - James Radford


答案:


你应该嘲笑 TokenManager 和 TokenValidator,然后创建两个单元测试用例:

  • 情况1: 令牌已经过验证 和 GetToken 被称为恰好一次
  • 案例2: 令牌未经过验证 和 GetToken 被称为两次

情况1:

[Test]
public void Subscribe_TokenIsValidated_GetTokenIsCalledOnce()
{
    // Arrange:
    var tokenManagerMock = Mock.Of<TokenManager>();

    var tokenValidatorMock = Mock.Of<TokenValidator>(x =>
        x.Validate(It.IsAny<Token>()) == true);

    var subscriber = new Subscriber
    {
        TokenManager = tokenManagerMock,
        TokenValidator = tokenValidatorMock
    };

    // Act:
    subscriber.Subscribe(It.IsAny<string>(), It.IsAny<string>(),
        It.IsAny<string>());

    // Assert:
    Mock.Get(tokenManagerMock).Verify(x =>
        x.GetToken(It.IsAny<string>(), It.IsAny<bool>()), Times.Once);
}

案例2:

[Test]
public void Subscribe_TokenIsExpiredOrInvalid_GetTokenIsCalledTwice()
{
    // Arrange:
    var tokenManagerMock = Mock.Of<TokenManager>();

    var tokenValidatorMock = Mock.Of<TokenValidator>(x =>
        x.Validate(It.IsAny<Token>()) == false);

    var subscriber = new Subscriber
    {
        TokenManager = tokenManagerMock,
        TokenValidator = tokenValidatorMock
    };

    // Act:
    subscriber.Subscribe(It.IsAny<string>(), It.IsAny<string>(),
        It.IsAny<string>());

    // Assert:
    Mock.Get(tokenManagerMock).Verify(x =>
        x.GetToken(It.IsAny<string>(), It.IsAny<bool>()), Times.Exactly(2));
}

或者,您可以创建单元测试而无需模拟 TokenValidator 并验证是否 GetToken() 被称为至少一次。但是,在第一个示例中创建两个案例是首选,因为我们正在测试所有代码路径。

// Arrange:
var tokenManagerMock = Mock.Of<TokenManager>();
var subscriber = new Subscriber {TokenManager = tokenManagerMock};

// Act:
subscriber.Subscribe(It.IsAny<string>(),
    It.IsAny<string>(),
    It.IsAny<string>());

// Assert:
Mock.Get(tokenManagerMock).Verify(x =>
        x.GetToken(It.IsAny<string>(), It.IsAny<bool>()), Times.AtLeastOnce);

有关Moq验证的更多信息,请访问:


14
2017-12-02 17:07



那真是太棒了。谢谢 - James Radford
别客气 ;) - Dariusz Woźniak


您可以使用Verify方法使用MOQ进行验证。喜欢这个:

var tokenManagerMock = new Mock<ITokenManager>();
var sut = new WhateverItIsCalled(tokenManagerMock.Object);
sut.Subscribe("ssss", "example@example.com", "XXX");
tokenManagerMock.Verify(m => m.GetToken(It.Is<string>(c => c == "ssss", It.Is<bool>(x => x == false)), Times.Once); 

您需要能够以某种方式将令牌管理器传递到您正在测试的系统中。通常通过ctor或可能是财产。

我建议你使用像AutoFixture这样的东西来消除“ssss”的丑陋并使事情变得更加干燥。

您可能需要使令牌管理器模拟返回适当的内容以通过验证。像这样的东西:

var tokenManagerMock = new Mock<ITokenManager>();
tokenManagerMock.Setup(m => m.GetToken(It.Is<string>(x => x == "ssss", It.IsAny<bool>()).Returns("XXXXXX");

0
2017-12-02 15:42



实际上,除非有必要,否则我建议使用It.IsAny <string>() - Justin Pihony