Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I get a series of good results and a thrown exception from Moq

Tags:

moq

I am mocking a wrapper to an MSMQ. The wrapper simply allows an object instance to be created that directly calls static methods of the MessageQueue class.

I want to test reading the queue to exhaustion. To do this I would like the mocked wrapper to return some good results and throw an exception on the fourth call to the same method. The method accepts no parameters and returns a standard message object.

Can I set up this series of expectations on the method in Moq?

like image 990
BlackWasp Avatar asked Jun 12 '09 08:06

BlackWasp


People also ask

What method allows for an exception to be outputted in MOQ?

Throws Method (Exception)

What is setup in MOQ?

Setup method is used to set expectations on the mock object For example: mock. Setup(foo => foo. DoSomething("ping")). Returns(true);


1 Answers

Yup, this is possible if you don't mind jumping through a few minor hoops. I've done this for one of my projects before. Alright here is the basic technique. I just tested it out in Visual Studio 2008, and this works:

var mockMessage1 = new Mock<IMessage>();
var mockMessage2 = new Mock<IMessage>();
var mockMessage3 = new Mock<IMessage>();

var messageQueue = new Queue<IMessage>(new [] { mockMessage1.Object, mockMessage2.Object, mockMessage3.Object });

var mockMsmqWrapper = new Mock<IMsmqWrapper>();

mockMsmqWrapper.Setup(x => x.GetMessage()).Returns(() => messageQueue.Dequeue()).Callback(() =>
{
    if (messageQueue.Count == 0)
        mockMsmqWrapper.Setup(x => x.GetMessage()).Throws<MyCustomException>();
});

A few notes:

  1. You don't have to return mocked messages, but it's useful if you want to verify expectations on each message as well to see if certain methods were called or properties were set.
  2. The queue idea is not my own, just a tip I got from a blog post.
  3. The reason why I am throwing an exception of MyCustomException is because the Queue class automatically throws a InvalidOperationException. I wanted to make sure that the mocked MsmqWrapper object throws an exception because of Moq and not because of the queue running out of items.

Here's the complete code that works. Keep in mind that this code is ugly in some places, but I just wanted to show you how this could be tested:

public interface IMsmqWrapper
{
    IMessage GetMessage();
}

public class MsmqWrapper : IMsmqWrapper
{
    public IMessage GetMessage()
    {
        throw new NotImplementedException();
    }
}

public class Processor
{
    private IMsmqWrapper _wrapper;
    public int MessagesProcessed { get; set; }
    public bool ExceptionThrown { get; set; }

    public Processor(IMsmqWrapper msmqWrapper)
    {
        _wrapper = msmqWrapper;        
    }

    public virtual void ProcessMessages()
    {
        _wrapper.GetMessage();
        MessagesProcessed++;
        _wrapper.GetMessage();
        MessagesProcessed++;
        _wrapper.GetMessage();
        MessagesProcessed++;

        try
        {
            _wrapper.GetMessage();
        }
        catch (MyCustomException)
        {
            ExceptionThrown = true;
        }
    }
}

[Test]
public void TestMessageQueueGetsExhausted()
{
    var mockMessage1 = new Mock<IMessage>();
    var mockMessage2 = new Mock<IMessage>();
    var mockMessage3 = new Mock<IMessage>();

    var messageQueue = new Queue<IMessage>(new [] { mockMessage1.Object, mockMessage2.Object, mockMessage3.Object });

    var mockMsmqWrapper = new Mock<IMsmqWrapper>();
    mockMsmqWrapper.Setup(x => x.GetMessage()).Returns(() => messageQueue.Dequeue()).Callback(() =>
    {
        if (messageQueue.Count == 0)
            mockMsmqWrapper.Setup(x => x.GetMessage()).Throws<InvalidProgramException>();
    });

    var processor = new Processor(mockMsmqWrapper.Object);

    processor.ProcessMessages();

    Assert.That(processor.MessagesProcessed, Is.EqualTo(3));
    Assert.That(processor.ExceptionThrown, Is.EqualTo(true));
}
like image 199
Praveen Angyan Avatar answered Oct 10 '22 22:10

Praveen Angyan