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

Stub protected method with out/ref params #223

Closed
franklin-ross opened this issue Dec 4, 2015 · 3 comments
Closed

Stub protected method with out/ref params #223

franklin-ross opened this issue Dec 4, 2015 · 3 comments
Assignees
Milestone

Comments

@franklin-ross
Copy link

Howdy, I can't seem to work out a way to stub a protected method with an out param. Is it possible? Is/could there be something like mock.Protected().Setup<Thing>("ImProtectedWithOut", ItExpr.IsAnyOut<int>())?

@stakx
Copy link
Contributor

stakx commented Jun 27, 2017

Hmm, this is tricky. Let me just throw out an idea here. Given that one of Moq's design goals is to provide a strongly-typed API (and .Protected() obviously has to violate that goal at least a little bit), and given that we currently don't support ref / out all that well, I think one possible way forward would be something like this:

// Define a delegate that has the exact same signature
// as the protected method that you want to set up in a mock:
delegate void ImProtectedWithOutAction(out int result);var mock = new Mock<Thing>();
// Then, using a (currently non-existent) generic overload of `Setup`, let Moq
// know what signature to expect from the protected method:
int result;
mock.Protected().Setup<ImProtectedWithOutAction>("ImProtectedWithOut",
                                                 method => method.Invoke(out result));

Different idea, but conceptually similar:

// Define an interface that describes all protected members of Thing you want to set up:
interface ProtectedMembersOfThing
{
    void ImProtectedWithOut(out int result);
}int result;
mock.Protected<ProtectedMembersOfThing>().Setup(thing => thing.ImProtectedWithOut(out result));

This would be preferable to idea (1) above if there are lots of protected members you want to set up. But it feels a little like an abuse of interface.

@stakx
Copy link
Contributor

stakx commented Sep 30, 2017

Visiting for triage: Let's look at this again once #105 has been implemented.

@stakx
Copy link
Contributor

stakx commented Oct 23, 2017

You'll be able to do this with Moq 4.8. Let's say you have e.g. this type that you'd like to mock:

public abstract class Foo
{
	public bool TryFiddle(string intact, out string fiddled)
	{
		return this.TryFiddleImpl(intact, out fiddled);
	}

	protected abstract bool TryFiddleImpl(string intact, out string fiddled);
}

To set up Foo.TryFiddleImpl, you might want to define a few helper types:

// type you declare to get at the protected member:
public interface FooImpl
{
	bool TryFiddleImpl(string intact, out string fiddled);
}

// delegate type you declare so you can setup a `.Returns` callback
// that can access the out parameter:
public delegate bool TryFiddleImplReturns(string intact, out string fiddled);

Then finally, you can put everything together e.g. as follows:

var mock = new Mock<Foo>();

string fiddled;
mock.Protected().As<FooImpl>()
        .Setup(m => m.TryFiddleImpl(It.IsAny<string>(), out fiddled))
	.Returns(new TryFiddleImplReturns((string i, out string o) =>
	{
		o = "(" + (i ?? "") + ")";
		return i != null;
	}));

if (mock.Object.TryFiddle("hello", out fiddled))
{
	Console.WriteLine(fiddled);
}

Admittedly, that's quite some work just to set up a method. Of course, if you have Foo under your control, it would be a lot easier to just have it formally implement FooImpl (whose method you could then mock directly)—but if Foo is not under your control, then at least mocking its protected method with a by-ref parameter is now possible.

@stakx stakx closed this as completed Oct 23, 2017
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

2 participants