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

时间:2012-09-26 10:31:51

标签: c# visual-studio-2010 unit-testing moq

我想测试一个构造,该构造在其中调用一个方法两次以获得两个不同的值

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

}

}

为了测试上面我使用单元测试类

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

}

上述方法通过,但codetext和datatext包含相同的值Motion 我希望他们设置为

codetext = Canada
datatext = Motion

我怎样才能实现这个目标?

我试过objMock.VerifyAll()未通过测试?

2 个答案:

答案 0 :(得分:5)

如果使用MOQ 4,可以使用SetupSequence,否则可以使用lambda

完成

使用SetupSequence非常自我解释。

使用lambdas不是太乱。重要的一点是,在声明设置时,返回值设置为。如果一个人刚刚使用

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

设置将始终返回片段[0]。通过使用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());

}

答案 1 :(得分:2)

Moq documentation可以使用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++);

这可以解决问题,但这不是最优雅的解决方案。 Matt Hamilton proposes在他的博客文章中更好一点,聪明地使用队列:

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

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

拨打mock.Object.getValueByCode两次,分别会生成"Canada""Motion"个字符串。