最小起订量设置重叠。如果在它之后设置任何案例和具体会怎样?

Moq setups overlapping. What will be if setup any case and concrete after it?

我想为调用设置 return 值,除了一种指定的情况外,任何参数都可以使用,而另一个 return 值则用于这种情况。以下代码是否提供预期的行为?测试通过了吗?是否保证遵循描述结构的其他可能情况?

interface ISomeInterface
{
    int SomeMethod(string param);
}

[TestMethod]
public void SomeClass_ShouldBehaveProperly_GivenSomeScenario()
{
    var mock = new Mock<ISomeInterface>(MockBehavior.Strict);
    mock.Setup(m => m.SomeMethod(It.IsAny<string>()))
        .Returns(1);
    mock.Setup(m => m.SomeMethod("aSpecificString"))
        .Returns(100);

    Assert.AreEquel(100, mock.Object.SomeMethod("aSpecificString"));
    Assert.AreEquel(1, mock.Object.SomeMethod("anyString"));
}   

混合设置怎么样,例如,当我们为任何参数设置 'throws exception',但为某些特定参数设置 'returns value' 时?

mock.Setup(m => m.SomeMethod(It.IsAny<string>()))
    .Throws<Exception>();
mock.Setup(m => m.SomeMethod("aSpecificString"))
    .Returns(100);

最后一个代码示例中提供的设置预期会有什么行为?


的已接受答案中我知道

The last call wins and nullifies previous calls

但是,当设置顺序相反时,我们有相同的行为吗?

But, do we have the same behavior when setups are in reverse order?

(不是这种情况)

测试后,似乎在更松散的匹配之后进行更具体的期望时,行为符合预期

例如

[TestMethod]
public void SomeClass_ShouldBehaveProperly_GivenSomeScenario() {
    var mock = new Mock<ISomeInterface>(); // Works for Strict or Loose
    mock.Setup(m => m.SomeMethod(It.IsAny<string>()))
        .Throws<InvalidOperationException>();
    mock.Setup(m => m.SomeMethod("aSpecificString"))
        .Returns(100);
    mock.Setup(m => m.SomeMethod("anotherString"))
        .Returns(1);

    Assert.AreEqual(100, mock.Object.SomeMethod("aSpecificString")); //PASS
    Assert.AreEqual(1, mock.Object.SomeMethod("anotherString")); //PASS
    Assert.ThrowsException<InvalidOperationException>(() => 
        mock.Object.SomeMethod("anyString")); //PASS
}

但是,如果多次执行相同的期望,则最后一个获胜

例如

[TestMethod]
public void SomeClass_ShouldBehaveProperly_GivenSomeScenario2() {
    var mock = new Mock<ISomeInterface>();
    mock.Setup(m => m.SomeMethod(It.IsAny<string>()))
       .Throws<InvalidOperationException>();
    mock.Setup(m => m.SomeMethod("aSpecificString"))
        .Returns(100);
    mock.Setup(m => m.SomeMethod("aSpecificString"))
        .Returns(1);

    Assert.ThrowsException<InvalidOperationException>(() => 
        mock.Object.SomeMethod("anyString")); //PASS
    Assert.AreEqual(100, mock.Object.SomeMethod("aSpecificString")); //Fail
}