【问题标题】:Calling a method twice with different values Unit testing using MOQ使用不同的值两次调用方法 使用 MOQ 进行单元测试
【发布时间】:2012-09-26 10:31:51
【问题描述】:

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

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() 没通过测试??

【问题讨论】:

  • 这可能不是最好的方法,但为什么不将 It.IsAny 替换为专门匹配 Canada 或 Motion 的特定值呢?不过,这感觉像是一个相当笨拙的解决方案。
  • 返回值与虚拟参数无关

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


【解决方案1】:

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

使用 SetupSequence 很容易解释。

使用 lambdas 并不太麻烦。重要的一点是返回值是在声明设置时设置的。如果刚刚使用过

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

设置总是返回pieces[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());

}

【讨论】:

  • 由于最小起订量版本,我不得不使用第二种方式,工厂就像一个魅力。非常感谢。
【解决方案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" 字符串。

【讨论】:

  • 这两种方法都很有趣,第一个方法都得到“加拿大”,第二个使用队列变得紧急。不适合我?
  • @Gauls:谢谢,第一个解决方案出现错误 - Returns 必须通过 lambda 延迟指定(现已修复)。不知道Queue 有什么问题,可以在我的盒子上使用。
猜你喜欢
  • 2012-06-01
  • 2021-10-15
  • 1970-01-01
  • 1970-01-01
  • 2011-12-24
  • 1970-01-01
  • 1970-01-01
  • 2018-03-29
相关资源
最近更新 更多