views:

56

answers:

2

I have a method called ProcessPayment() that I'm developing via BDD and mspec. I need help with a new challenge. My user story says:

Given a payment processing context,
When payment is processed with valid payment information,
Then it should return a successful gateway response code.

To set up the context, I am stubbing my gateway service using Moq.

_mockGatewayService = Mock<IGatewayService>();
_mockGatewayService.Setup(x => x.Process(Moq.It.IsAny<PaymentInfo>()).Returns(100);

Here's the spec:

public class when_payment_is_processed_with_valid_information {

    static WebService _webService;
    static int _responseCode;
    static Mock<IGatewayService> _mockGatewayService;
    static PaymentProcessingRequest _paymentProcessingRequest;

    Establish a_payment_processing_context = () => {

        _mockGatewayService = Mock<IGatewayService>();
        _mockGatewayService
            .Setup(x => x.Process(Moq.It.IsAny<PaymentInfo>())
            .Returns(100);

        _webService = new WebService(_mockGatewayService.Object);

        _paymentProcessingRequest = new PaymentProcessingRequest();
    };

    Because payment_is_processed_with_valid_payment_information = () => 
        _responseCode = _webService.ProcessPayment(_paymentProcessingRequest); 

    It should_return_a_successful_gateway_response_code = () => 
        _responseCode.ShouldEqual(100);

    It should_hit_the_gateway_to_process_the_payment = () => 
        _mockGatewayService.Verify(x => x.Process(Moq.It.IsAny<PaymentInfo>());

}

The method should take a `PaymentProcessingRequest' object (not domain obj), map that obj to a domain obj, and pass the domain obj to the stubbed method on the gateway service. The response from the gateway service is what gets returned by the method. However, because of the way I am stubbing my gateway service method, it doesn't care what gets passed in to it. As a result, it seems I have no way to test whether or not the method maps the request object to the domain object properly.

When can I do here and still adhere to BDD?

+2  A: 

To check that the object sent to your IGatewayService is correct, you can use a callback to set a reference to the domain object. You can then write your assertions on properties of that object.

Example:

_mockGatewayService
            .Setup(x => x.Process(Moq.It.IsAny<PaymentInfo>())
            .Callback<PaymentInfo>(paymentInfo => _paymentInfo = paymentInfo);
Derek Greer
A: 

So from what I understand,
You want to test the mapping logic in the WebService.ProcessPayment method ; there is a mapping of an input parameter A to an object B, which is used as an input to a GateWayService collaborator.

It should_hit_the_gateway_to_process_the_payment = () => 
        _mockGatewayService.Verify(
             x => x.Process( Moq.It.Is<PaymentInfo>( info => CheckPaymentInfo(info) ));

Use the Moq It.Is constraint which takes in a Predicate (a test for the argument to satisfy). Implement CheckPaymentInfo to assert against the expected PaymentInfo.

e.g. to check if Add is Passed an even number as an argument,

 mock.Setup(foo => foo.Add(It.Is<int>(i => i % 2 == 0))).Returns(true); 
Gishu