简体   繁体   English

使用不同值调用方法两次使用MOQ进行单元测试

[英]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和datatext包含我希望它们设置的相同值Motion

codetext = Canada
datatext = Motion

How can i achieve this? 我怎样才能实现这一目标?

I have tried objMock.VerifyAll() which fails the test ?? 我试过objMock.VerifyAll()没有通过测试?

If using MOQ 4 one can use SetupSequence, else it can be done using a lambda 如果使用MOQ 4,可以使用SetupSequence,否则可以使用lambda完成

Using SetupSequence is pretty self explanatory. 使用SetupSequence非常自我解释。

Using the lambdas is not too messy. 使用lambdas不是太乱。 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]. 设置将始终返回片段[0]。 By using the lambda, the evaluation is deferred until Bar() is invoked. 通过使用lambda,延迟评估直到调用Bar()。

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());

}

Moq documentation says you can simulate something like successive returns with Callback method: Moq文档说你可以Callback方法模拟连续返回的东西:

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: Matt Hamilton在他的博客文章中提出了更好的一个,聪明地使用队列:

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. 调用mock.Object.getValueByCode两次,将分别生成"Canada""Motion"字符串。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM