Moq4: Fix multiple Mock.Setup() with Expression<Func<T>> invocation

Created on 5 Feb 2018  路  6Comments  路  Source: moq/moq4

I'm trying to use multiple Mock.Setup() invocation for the same mocked object method.

It works fine, when i'm using code like that:

[TestMethod]
pubblic void TestMethod1()
{
    var mock = new Mock<ITestInt>();

    mock.Setup(_ => _.Do(true)).Returns(1);
    mock.Setup(_ => _.Do(false)).Returns(-1);

    //---

    var trueResult = mock.Object.Do(true);
    var falseResult = mock.Object.Do(false);

    //---

    Assert.AreEqual(trueResult,1); // true
    Assert.AreEqual(falseResult, -1); // true
}

But, when i'm trying to execute Mock.Setup() method with Expression>, it fails. A little code example:

[TestMethod]
public void TestMethod2()
{
    var mock = new Mock<ITestInt>();

    Expression<Func<bool>> func = () => It.Is<bool>(_ => true);
    mock.Setup(_ => _.Do(func.Compile().Invoke())).Returns(1);

    Expression<Func<bool>> func2 = () => It.Is<bool>(_ => false);
    mock.Setup(_ => _.Do(func2.Compile().Invoke())).Returns(-1);

    //---

    var trueResult = mock.Object.Do(true);
    var falseResult = mock.Object.Do(false);

    //---

    Assert.AreEqual(trueResult, 1); // true
    Assert.AreEqual(falseResult, -1); // FAIL, falseResult equals 1 instead of -1
}

Most helpful comment

Because in real life It.Is<bool>(_ => true) can be replaced with It.Is<bool>(_ => _.Id > 0 && _.Id < 1000) or something else, that can't be specified with a simple plain arg value.

All 6 comments

@msharonov:

But, when i'm trying to execute Mock.Setup() method with Expression, it fails. A little code example: [...]

Your second code example does not make any sense to me. Could you perhaps show the definition of the ITestInt.Do method that goes along with it, as well as a description what you're trying to achieve with the second test? Why is it so radically different from the first test?

Of course, my bad. Here is the whole ITestInt simple interface definition:

public interface ITestInt
{
    int Do(bool arg);
}

I'm trying to archieve only one goal: take ability to define mocking method args with an expression, that received outside of initalization method. Little exampple

[TestMethod]
public void TestMethod3()
{
    var mock = new MockDefinition();

    mock
        .Setup(() => It.Is<bool>(_ => true), 1)
        .Setup(() => It.Is<bool>(_ => false), -1);

    //---

    var trueResult = mock.Do(true);
    var falseResult = mock.Do(false);

    //---

    Assert.AreEqual(trueResult, 1);
    Assert.AreEqual(falseResult, -1); // fails here
}

public sealed class MockDefinition : ITestInt
{
    private readonly Mock<ITestInt> _mock = new Mock<ITestInt>();

    public MockDefinition Setup(Expression<Func<bool>> setupFuncExp, int result)
    {
        _mock.Setup(_ => _.Do(setupFuncExp.Compile().Invoke())).Returns(result);

        return this;
    }

    public int Do(bool arg)
    {
        return _mock.Object.Do(arg);
    }
}

Why all the Expression stuff? Why don't you just use a plain bool argument instead of an Expression<Func<bool>>?

Because in real life It.Is<bool>(_ => true) can be replaced with It.Is<bool>(_ => _.Id > 0 && _.Id < 1000) or something else, that can't be specified with a simple plain arg value.

Well in that case the problem can be reduced to passing the proper expression tree to Setup.

Note that Setup expects an expression tree. Therefore .Compile().Invoke() won't be executed, but instead it'll be transformed to an equivalent LambdaExpression. That's not what you want.

You will likely need to build the whole expression yourself, e.g. Expression.Call(setupMockParamExpr, typeof(ITestInt).GetMethod("Do"), exprRepresentingCallToMatcherFn) and pass that as the expression body to Setup.

This appears to be a pure usage question (not a request for an enhancement, nor a bug report) and it's mostly about LINQ expression trees, as far as I can tell. Do you agree?

Oh. Yes, you're right. Thanx!)

Was this page helpful?
0 / 5 - 0 ratings