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

Capture with ProtectedSetup #934

Closed
cheng93 opened this issue Oct 3, 2019 · 6 comments
Closed

Capture with ProtectedSetup #934

cheng93 opened this issue Oct 3, 2019 · 6 comments

Comments

@cheng93
Copy link

cheng93 commented Oct 3, 2019

Capture's with ProtectedSetup does not work.

For example

HttpRequestMessage request = null;
var captureMatch = new CaptureMatch<HttpRequestMessage>(x => request = x);
this.httpMessageHandlerMock
    .Protected()
    .Setup<Task<HttpResponseMessage>>(
        "SendAsync",
        Capture.With(captureMatch),
        //ItExpr.IsAny<HttpRequestMessage>(),
        ItExpr.IsAny<CancellationToken>())
    .ReturnsAsync(new HttpResponseMessage());

throws the following exception

System.ArgumentException : Use ItExpr.IsNull<TValue> rather than a null argument value, as it prevents proper method lookup.

Expected outcome
request is captured

@cheng93 cheng93 changed the title CaptureGroup with ProtectedSetup Capture with ProtectedSetup Oct 3, 2019
@stakx
Copy link
Contributor

stakx commented Oct 4, 2019

Thanks for reporting. Looks like we're missing something like CaptureExpr (as with ItItExpr) though it would be nice to avoid having to add that to the API, if possible. I'll look into this in some more detail during the next few days.

@cheng93
Copy link
Author

cheng93 commented Oct 4, 2019

If you're happy with CaptureExpr, I can submit a PR for it.

Otherwise, I'll leave it to you

@stakx
Copy link
Contributor

stakx commented Oct 4, 2019

If you're happy with CaptureExpr [...]

I can't say that I am (see my post above). I'd first like to check for alternative solutions. If there aren't any better solutions, I'll get back to you about CaptureExpr!

@stakx
Copy link
Contributor

stakx commented Oct 24, 2020

@cheng93, sorry for the long silence. I've been busy. It's a shame I didn't think of this before, but there's actually already a way to use Capture with setups for protected methods, using .Protected().As<T>().

Say this is the type you're going to mock:

public abstract class Foo
{
    public void InvokeMethod(string arg) => Method(arg);

    protected abstract void Method(string arg);
}

You want to set up the protected method, Method. Define an interface that has a method with the same signature (i.e. same name, parameters, and return type):

public interface FooProtectedMembers
{
    void Method(string arg);
}

Note that the type to be mocked (Foo) does not need to implement this interface!

Now you can set up Foo.Method including Capture as follows:

var fooMock = new Mock<Foo>();
var capturedArgs = new List<string>();
fooMock.Protected().As<FooProtectedMembers>().Setup(foo => foo.Method(Capture.In(capturedArgs)));

That is, .Protected().As<T>() allows you to access protected methods on the mocked type via a look-alike type T whose (public) members mirror some or all of the protected members of the mocked type. While foo.Method in your setup expression refers to FooProtectedMembers.Method, Moq will transparently replace that with a reference to Foo.Method.

Let's verify that it actually works:

fooMock.Object.InvokeMethod("hello");
fooMock.Object.InvokeMethod("bye");

Assert.Equal(new[] { "hello", "bye" }, capturedArgs);

Let me know if this solution is sufficient. If I don't hear back from you sometime during the next two weeks or so, I'm going to assume it is & I'll close this as resolved.

@siprbaum
Copy link

Wow, this is a very neet trick! I was suggesting to add this to the quick start guide, but I just noticed that the information was mentioned there, but not as easily accessible as it was done in the above example. So I extended the quick start wiki examples make it more accessible.

@cheng93
Copy link
Author

cheng93 commented Oct 26, 2020

Works quite well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants