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

Question about order of Setup #831

Closed
dezsiszabi opened this issue May 22, 2019 · 4 comments
Closed

Question about order of Setup #831

dezsiszabi opened this issue May 22, 2019 · 4 comments

Comments

@dezsiszabi
Copy link

dezsiszabi commented May 22, 2019

I have a question about the significance of the order of the Setup statements.

I was converting a large amount of tests (~3000) from Rhino Mocks to Moq and some of my tests were failing because of the following behavior.

public interface IFoo
{
    int Test(string value, string valueTwo);
}

var mock = new Mock<IFoo>();
mock.Setup(foo => foo.Test(Moq.It.IsAny<string>(), Moq.It.IsAny<string>())).Returns(2);
mock.Setup(foo => foo.Test("foo", "bar")).Returns(1);
mock.Object.Test("foo", "bar"); // Returns 1

// Now with different Setup order

var mock = new Mock<IFoo>();
mock.Setup(foo => foo.Test("foo", "bar")).Returns(1);
mock.Setup(foo => foo.Test(Moq.It.IsAny<string>(), Moq.It.IsAny<string>())).Returns(2);
mock.Object.Test("foo", "bar"); // Returns 2

This indicates that the order of the setups matter and generally it should be least specific to most specific. I didn't really find documentation about this (maybe wasn't looking too hard), but can you confirm wether this is intended behavior?

For some reason I thought that finding the best match is done by the library and not affected by the order (only if you're overriding a previous Setup).

@stakx
Copy link
Contributor

stakx commented May 22, 2019

generally it should be least specific to most specific

That's generally a good rule of thumb to follow. Later setups always take preference over earlier ones, and that is definitely the intended behavior of Moq (even if it isn't explicitly documented).

@stakx stakx closed this as completed May 22, 2019
@dezsiszabi
Copy link
Author

dezsiszabi commented May 23, 2019

Thank you.
I might have some other questions as well, so please bear with me. This is about setting out parameters.

In the quickstart guide this is the example for this:

// out arguments
var outString = "ack";
// TryParse will return true, and the out argument will return "ack", lazy evaluated
mock.Setup(foo => foo.TryParse("ping", out outString)).Returns(true);

Is it possible to introduce something similar to how Rhino Mocks does this, so I don't have to declare a local variable? In Rhino I can do:

mock.Stub(foo => foo.TryParse(Arg.Is("ping"), out Arg<string>.Out("ack").Dummy));

There is no need to declare a local variable, can pass in constants, or conditional expressions (ternary etc), I don't get ReSharper warnings about the local variable.

I tested this in Moq and it worked for me with the following class (naming is not the best):

public class Out<T>
{
    public T Value;

    private Out(T value)
    {
        Value = value;
    }
   
    public static Out<T> Set(T value) => new Out<T>(value);
}

Moq works with this as well:

mock.Setup(foo => foo.TryParse("ping", out Out<string>.Set("ack").Value)).Returns(true);

I would be happy to see this as part of Moq if you don't see an issue with it. Right now I have to implement a shared testing utils project to share amongst my tests if I want something similar.

Opinion?

@dezsiszabi
Copy link
Author

dezsiszabi commented Jun 10, 2019

I don't see the response here, although I did receive an e-mail notification:

Just use a C# discard (out _).

I don't think that solves what I was asking.

  1. discards cannot be used in expression trees (CS8207)
  2. my previous post was about setting the out parameter values without a local variable, so I don't really understand how using discards is related to my question.

@stakx
Copy link
Contributor

stakx commented Jun 10, 2019

I don't see the response here, although I did receive an e-mail notification [...]

The reason you don't see that response here (anymore) is because I deleted it. If I had read your second post more carefully before posting it, I wouldn't have posted it in the first place as it's clear that you're definitely not looking for C# discards. 😆

However it seems I somehow forgot to post a revised reply; my apologies for that mistake.

Opinion?

Regarding your suggested feature, I don't think this needs to go into Moq. The fact that Moq actually reads an out parameter is already strange enough, I don't think we should build up this part of the API any further. And, as you showed yourself, it's quite possible to do this outside of the library.

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