什么是测试对象和协作者?

时间:2014-05-05 05:50:18

标签: c# mocking moq

我正在试图弄清楚如何使用Moq进行我的第一次模拟。我也很嘲笑。

假设我有以下TDD测试:

[TestMethod]
public void PreAuthorize_WithEmptyRequest_ReturnsNonNullResponse()
{
    // Arrange
    var preAuthorizeRequest = new PreAuthorizeRequest();

    // Act
    var authorizeResponse = _dataProcessor.SendRequest(preAuthorizeRequest);

    // Assert
    Assert.IsNotNull(authorizeResponse);
}

上面那个测试的场景是,如果我们发送一个没有状态的对象实例,我们仍然应该找回一个响应对象(它不会爆炸)。所以我想在Mock和Stub术语中我想我想测试dataProcessor的SendRequest方法的行为,因为它会发回PreAuthorizeResponse的实例....对吗?

现在这里有关于这些类型的信息:

    public interface IPaymentRequest
    {
        string SecurityToken { get; set; }
        int RetailID { get; set; }
        int ProcessorId { get; set; }
    }

    public class PreAuthorizeRequest : IPaymentRequest
    {
        public string SecurityToken { get; set; }
        public int RetailID { get; set; }
        public int ProcessorId { get; set; }
        public PreAuthorizeTransaction Transaction { get; set; }
    }

       public IPaymentResponse SendRequest(IPaymentRequest request)
        {
            ITransaction transaction = PaymentUtilities.GetPaymentRequestTransactionType(request);
            IPaymentResponse response = PaymentUtilities.GetPaymentResponseType(request);
            var transactionType = PaymentUtilities.GetPaymentRequestTransactionTypeEnum(request);
            var requestValidator = new PaymentRequestValidator();

            requestValidator.ValidateRequest(request);

            var requestIsValid = requestValidator.RequestIsValid;

            if (!requestIsValid)
            {
                response = PaymentUtilities.BuildPaymentResponse(request, requestValidator, transaction, transactionType);
                return response;
            }
IAutoPaymentProcessor autoPaymentProcessor = CreateAutoPaymentProcessor(request);
            var configValidator = new ConfigurationValidator(autoPaymentProcessor);

            configValidator.ValidateConfigurationSettings();
            bool settingsAreValid = configValidator.ConfigIsValid;

            if (!settingsAreValid)
            {
                response = PaymentUtilities.BuildPaymentResponse(request, requestValidator, transaction, transactionType);
                return response;
            }

            response = SetConfigSettings(request, response);

            Document dataResponseDoc = SendRequest(request, response);
            response.PaymentProcessorId = (int)Enums.PaymentProcessorType.Data;
            response.ProviderAuthCode = dataResponseDoc != null ? dataResponseDoc.get("Response.authcode") : string.Empty;
            response.ProviderReference = dataResponseDoc != null ? dataResponseDoc.get("Response.data_reference") : string.Empty;

            return response;
        }

所以我没有看到需要模拟,换句话说是模拟权限上的验证调用?我想我只需要一个存根并测试我是否得到了PreAuthorizeResponse的实例。所以我猜这是Moq的存根吧?

那么如果我对我只是需要使用存根,我将如何使用Moq呢?

我试过这个,但我觉得这是错的,因为我觉得SUT是我的数据处理器,我相信你不应该在测试中嘲笑对象:

    [TestMethod]
public void PreAuthorize_WithEmptyRequest_ReturnsNonNullResponse()
{
    // Arrange - setup data
    var dataProcessorStub = new Mock<IPaymentProcessor>();
    var preAuthorizeRequest = new PreAuthorizeRequest();

    // Act
    //setup - expectations
    dataProcessorStub.Setup(p => p.SendRequest(It.IsAny<PreAuthorizeRequest>())).Returns(It.IsAny<PreAuthorizeResponse>());

    // excercise
    var preAuthorizeResponse = dataProcessorStub.Object.SendRequest(preAuthorizeRequest);

    // Assert
    Assert.IsInstanceOfType(preAuthorizeResponse, typeof(PreAuthorizeResponse));
}

2 个答案:

答案 0 :(得分:1)

不,你真的不想嘲笑你想要测试的对象。您应该模拟该对象的依赖项(例如数据库对象)。

dataProcessor是被测对象(也称为被测系统),其他一切都是协作者(SUT的依赖关系)。

由于SendRequest方法中存在的硬依赖性数量很多,您将很难对此进行正确测试。

至少,您想要模拟PaymentRequestValidator,以便在发送特定类型的请求时,您可以让模拟设置说它无效,然后在代码,这反过来会导致SendRequest方法返回响应。

要实现这一点,您需要重构代码,以便传递请求验证器的模拟实例。此外,可能还有很多其他对象。

例如,您很可能需要模拟PaymentUtilities对象,以便您可以使用您使用的方法返回Mock对象,这些对象本身设置为返回此测试的特定内容。类似地,ConfigurationValidator - 它会在从测试中调用它时返回一个有效的配置(可能是一个不同的测试),或者你是否也需要模拟它?

这很好地进入了依赖注入控制反转的领域。我不是通过提供链接来侮辱你,但是这些主题在印刷品和网络上都有很好的文献资料。

答案 1 :(得分:0)

查看代码,如果您尝试测试SendRequest方法,似乎您不需要进行任何模拟。您需要模拟您要测试的内容的依赖关系,而不是测试对象本身。因此,如果您的PaymentProcessor测试需要任何外部依赖项,则需要模拟这些依赖项。

SendRequest方法确实采用了可以模拟的界面,但只是传递新创建的PreAuthorizeRequest

[TestMethod]
public void PreAuthorize_WithEmptyRequest_ReturnsNonNullResponse()
{
    // Arrange
    var preAuthorizeRequest = new PreAuthorizeRequest();

    // Act
    var authorizeResponse = _dataProcessor.SendRequest(preAuthorizeRequest);

    // Assert
    Assert.IsNotNull(authorizeResponse);
}

或者您可以模拟请求:

 [TestMethod]
 public void PreAuthorize_WithEmptyRequest_ReturnsNonNullResponse()
 {
     // Arrange
     var request = new Mock<IPaymentRequest>();

     // Act
     var authorizeResponse = _dataProcessor.SendRequest(request);

     // Assert
     Assert.IsNotNull(authorizeResponse);
 }