MVVM unit tests - message bus only works once

492 views Asked by At

I am trying to write some unit tests against a view model using SimpleMvvmToolkit, and several of these tests require a message be sent to the message bus to fire events inside the view model. The problem is it appears that I can only 'use' the message bus once; the first test that sends a message passes, but the other two that send a message fail. But if I run each test individually, all three pass, and if I change the order, the first test, no matter which one it is, passes.

Here is a sample of one of the tests.

[TestMethod]
public void DeleteRequest()
{
    // mock the driver transaction service

    var driverTransactionService =
         new Mock<Services.IDriverTransactionService>();

    var viewModel = new ValidationRequestViewModel(
         driverTransactionService.Object);

    driverTransactionService.Setup(dts =>
         dts.DeleteValidationRequest(It.IsAny<Action<int>>(), 
              It.IsAny<Action<Exception>>(),
              It.IsAny<int>()))
        .Callback((Action<int> action, Action<Exception> ex, int id) => 
             action.Invoke(requestId));

    // make a validation request and add to the collection

    var validationRequest = new ValidationRequest...

    var collection = viewModel.ValidationRequestView.SourceCollection as 
         ObservableCollection<ValidationRequest>;

    collection.Add(validationRequest);

    //  delete the validation request; send the confirmation message as if
    //  the user clicked yes

    viewModel.DeleteValidationRequest(validationRequest);

    MessageBus.Default.Notify(
         NotificationMessages.DeleteValidationRequestConfirmation, 
         this, new NotificationEventArgs<String>(null, null));

    // verify the service call was made

    driverTransactionService.Verify(dts => 
         dts.DeleteValidationRequest(It.IsAny<Action<int>>(), 
              It.IsAny<Action<Exception>>(), requestId));
}

So I am creating a mock of a service (which is a wrapper around a WCF service) and verifying that DeleteValidatonRequest on the service is being called. In this case, the message bus is needed because a confirmation dialog would normally pop up and send the DeleteValidationRequestConfirmation message if the user clicks OK.

The test fails on the last line (Verify) and when I debug, the handler for the message in the view model never executes so it looks like the message is never actually sent. Again, this only fails if the test is not the first test to send a message to the bus. If it executes alone or is the first, the test passes.

Any ideas? All of the tests are independent and do not share any properties or variables of the test class so I don't see how they could be stepping on each other.

EDIT: I used reflection to call the protected methods on the view model that the messages would normally fire; this gets me the code coverage I want, it just doesn't verify that the view model is responding to messages correctly.

EDIT 2: Crap, the same thing is happening with PropertyChanged events on the view model. The event handler only fires if the test is run independently or is the first.

1

There are 1 answers

3
cadrell0 On BEST ANSWER

I'm not familiar with SimpleMvvmToolkit, but I am familiar with the concept of messaging.

Don't use MessageBus.Default. Modify your ViewModels to have a MessageBus, or IMessageBus if it exists, constructor parameter. Now your tests will be isolated, so you can run them all at once and they should pass.

Additionally, if the IMessageBus interface exists, you can Mock it, which should make it even easier to test your ViewModels.