Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling a method twice with different values Unit testing using MOQ

I want to test a construct which calls a method within it twice to get two different values

public class  stubhandler
{

public stubhandler()
{

string codetext = model.getValueByCode(int a,string b); // 1,"High"    result Canada
string datatext = model.getValueByCode(int a,string b); // 10, "Slow"   result Motion

}

}

To test the above i use a unit test class

[TestMethod]
public void StubHandlerConstructor_Test()
{
Mock<Model> objMock = new Mock<>(Model);
objMock.Setup(m => m.getValueByCode(It.IsAny<int>,It.IsAny<string>)).Returns("Canada");

objMock.Setup(m => m.getValueByCode(It.IsAny<int>,It.IsAny<string>)).Returns("Motion");

stubhandler  classstubhandler = new stubhandler();

}

The above method pass but codetext and datatext contains same value Motion i want them to set to

codetext = Canada
datatext = Motion

How can i achieve this?

I have tried objMock.VerifyAll() which fails the test ??

like image 626
Gauls Avatar asked Sep 26 '12 10:09

Gauls


Video Answer


2 Answers

Moq documentation says you can simulate something like successive returns with Callback method:

var values = new [] { "Canada", "Motion" };
int callNumber = 0;

mock.Setup(m => m.getValueByCode(It.IsAny<int>(), It.IsAny<string>()))
    .Returns((i,s) => values[callNumber])
    .Callback(() => callNumber++);

This will do the trick, but it's not the most elegant solution. Matt Hamilton proposes much better one in his blog post, with clever use of queue:

var values = new Queue<string> { "Canada", "Motion" };

mock.Setup(m => m.getValueByCode(It.IsAny<int>(), It.IsAny<string>()))
    .Returns(() => values.Dequeue());

Calling mock.Object.getValueByCode twice, will produce "Canada" and "Motion" strings respectively.

like image 29
k.m Avatar answered Oct 19 '22 22:10

k.m


If using MOQ 4 one can use SetupSequence, else it can be done using a lambda

Using SetupSequence is pretty self explanatory.

Using the lambdas is not too messy. The important point to not it that the return value is set at the time that the setup is declared. If one just used

mockFoo.Setup(mk => mk.Bar()).Returns(pieces[pieceIdx++]);

the setup would always return pieces[0]. By using the lambda, the evaluation is deferred until Bar() is invoked.

public interface IFoo {
    string Bar();
}

public class Snafu {

    private IFoo _foo;
    public Snafu(IFoo foo) {
        _foo = foo;
    }

    public string GetGreeting() {
        return string.Format("{0} {1}",
                             _foo.Bar(),
                             _foo.Bar());
    }

}

[TestMethod]
public void UsingSequences() {

    var mockFoo = new Mock<IFoo>();
    mockFoo.SetupSequence(mk => mk.Bar()).Returns("Hello").Returns("World");

    var snafu = new Snafu(mockFoo.Object);

    Assert.AreEqual("Hello World", snafu.GetGreeting());

}

[TestMethod]
public void NotUsingSequences() {

    var pieces = new[] {
            "Hello",
            "World"
    };
    var pieceIdx = 0;

    var mockFoo = new Mock<IFoo>();
    mockFoo.Setup(mk => mk.Bar()).Returns(()=>pieces[pieceIdx++]);

    var snafu = new Snafu(mockFoo.Object);

    Assert.AreEqual("Hello World", snafu.GetGreeting());

}
like image 168
AlanT Avatar answered Oct 19 '22 22:10

AlanT