Narayana
Narayana

Reputation: 2744

Test a method that does something as well as throws an exception

I'm getting started with TDD (and MoQ). I have a method that takes in an Order and creates a unique CustomerId for that Order.

public class CustomerService
    {

        public CustomerService(IOrderRepository orderRepo)
        {
            _orderRepo = orderRepo;
        }

        public string Create(Order order)
        {
            //1. Save the Order that comes in, irrespective of being valid or not.
            _orderRepo.Save(order);

            //2. If the order is invalid, throw an exception.
            if (!isValid(order))
                throw new ArgumentException();

            //3. Create a Customer, generate a unique CustomerId and return that.
            return createCustomerAndGenerateCustomerId(order);
        }

    }

The following test doesn't seem to be working correctly:

    [Test]
    [ExpectedException(typeof(ArgumentException))]
    public void Create_WhenPassedInvalidOrder_StillPersistsIt()
    {
        //Arrange
        var order = new Order(); //This is invalid, as it has some mandatory fields missing
        var mockOrderRepo = new Mock<IOrderRepository>();
        var customerService = new CustomerService(mockOrderRepo.Object);

        //Act
        customerService.Create(order);  //This should call Save() on the order repo, but still throw an exception.

        //Assert
        mockOrderRepo.Verify(o => o.Save(order), Times.Once());
    }

This test is always passing, even if I don't call _orderRepo.Save(). What am I doing wrong?

Upvotes: 1

Views: 41

Answers (1)

nemesv
nemesv

Reputation: 139758

You cannot use ExpectedException in this scenario because Nunit will try/catch the exception on the test level so your mockOrderRepo.Verify never gets called.

So you manually need to try catch your customerService.Create call - and if you want manually assert on the thrown exception - or you the Assert.Throws if you're using Nunit 2.5 or higher:

[Test]
public void Create_WhenPassedInvalidOrder_StillPersistsIt()
{
    //Arrange
    var order = new Order(); 
    var mockOrderRepo = new Mock<IOrderRepository>();
    var customerService = new CustomerService(mockOrderRepo.Object);

    //Act
    Assert.Throws<ArgumentException>(() => customerService.Create(order));

    //Assert
    mockOrderRepo.Verify(o => o.Save(order), Times.Once());
}

Upvotes: 1

Related Questions