Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix multiple Mock.Setup() with Expression<Func<T>> invocation #584

Closed
vopvop opened this issue Feb 5, 2018 · 6 comments
Closed

Fix multiple Mock.Setup() with Expression<Func<T>> invocation #584

vopvop opened this issue Feb 5, 2018 · 6 comments

Comments

@vopvop
Copy link

vopvop commented Feb 5, 2018

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<Func>, 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
}
@vopvop vopvop changed the title Fix multiple Mock.Setup() with expression Fix multiple Mock.Setup() with Expression<Func<T>> invocation Feb 5, 2018
@stakx
Copy link
Contributor

stakx commented Feb 7, 2018

@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?

@vopvop
Copy link
Author

vopvop commented Feb 7, 2018

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

@stakx
Copy link
Contributor

stakx commented Feb 8, 2018

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

@vopvop
Copy link
Author

vopvop commented Feb 8, 2018

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.

@stakx
Copy link
Contributor

stakx commented Feb 8, 2018

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?

@vopvop
Copy link
Author

vopvop commented Feb 8, 2018

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

@vopvop vopvop closed this as completed Feb 8, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants