Moq4: Update existing mock using Expression

Created on 6 Oct 2016  路  9Comments  路  Source: moq/moq4

Hi, I'm trying to use Linq to Mocks to update an existing mock, in the same way I use it to create the mock:

Expression<Func<IClaimContext, bool>> initialSetup = cc => cc.GetClaim() == new Claim(123);

var claimContext = Mock.Of<IClaimContext>(initialSetup);

Assert.AreEqual(123, claimContext.GetClaim().ClaimId);


Expression<Func<IClaimContext, bool>> updateSetup = cc => cc.GetClaim() == new Claim(321);

var mock = Mock.Get(claimContext);

// TO DO: Pass updateSetup to mock...

Assert.AreEqual(321, claimContext.GetClaim().ClaimId);

How should I write the missing code to use "updateSetup" so that my second assert passes?

It works with this, instead of using the expression,

mock.Setup(cc => cc.GetClaim()).Returns(new Claim(321));

but if I have multiple setups the code would look much better with Linq to Mocks, and I want to pass the expression as a parameter.

Thanks

enhancement unresolved up-for-grabs

All 9 comments

I think defining what it means to update can get quite tricky really fast, and expectations will fall short all over. For example, are you intending to replace _all_ method calls or are you going to match by parameters too and only replace those that match with the update expression?

I agree the feature looks interesting. Something like mock.Update(expression)...

An Update method that gets an expression and changes the returned value for matched parameters would be nice. It should do the the same thing as mock.Setup().Returns(), but in a compact way.
It's actually a setup, but Setup already has a signature what gets an expression, but does something else.

@soringp: I agree that the update expression should be treated & have the same effect as several combined Setups.

I'd like to bring up one additional point. Like @davidshen84 suggested in #229, this is obviously a convenience feature (it doesn't do anything that Moq can't already do some other way, but it does it in a more compact way), therefore it should be convenient to use. Given that Mock.Of<T> doesn't return a Mock on which you could immediately call mock.Update, it should be possible to call Update without having to go through Mock.Get first. Therefore I propose that the new method be made static, i.e.:

partial class Mock
{
    public static void Update<T>(T mocked, Expression<Func<T, bool>> updateExpression);
}

Any opinions on this?

Is anyone still interested in this feature at all?

@stakx Sorry for the delay, but yes, I'm still interested in this feature and I like the proposed method.

As a side note, I like compact code and this proposed Update will look very nice, but I have some reservations regarding the expression syntax. For the untrained eye it looks a bit dodgy. Too bad we cannot replace == with a more meaningful operator.

If you add this method I think I will also add a local extension to update the mock:

public static void Update<T>(this Mock<T> mock, Expression<Func<T, bool>> expression) where T:class
{
     Mock.Update(mock.Object, expression);
}

Thanks for your interest in this.

Too bad we cannot replace == with a more meaningful operator.

It is indeed too late for that kind of change. But I'm curious, which operator would've been more meaningful in your opinion, and why?

The assignment operator or the lambda operator could have been good alternatives but the first is not allowed in expressions and I don't see how you could use the latter without some language changes.

It was just a silly idea, only equals works. I guess I was thinking more of using an alias or a custom operator, but this is not possible with C# so case closed :)

I think I would name the method SetupSo (SetupSuchThat?). That would emphasize that the expression is what you want to happen to your mock.

Closing this dormant issue, but marking it as "unresolved" so it can be easily found again. Please see #642 for details. If you'd like to pick this up and work on it, please post here briefly and we'll see what we can do!

Was this page helpful?
0 / 5 - 0 ratings