Substitute for same class I'm testing?

789 views
Skip to first unread message

t_elsmore

unread,
Jun 28, 2012, 10:02:15 AM6/28/12
to NSubstitute
I am getting the hang of the Arg.Do and .Returns operators, but I seem
to have missed something that should have been obvious: you can't run
these on non-substitutes or you'll get errors. Is this correct? I'm
trying to test a large method that calls 2 other methods. Rather than
test those methods in the same unit test, I'd rather set return
values, but when I try, I'm getting null errors because it's trying to
run those methods rather than setup nsubstitute return values. For
instance:
myClassName {
myMethod()
{
code I want to test here
callMethodTwo(variable);
more code I want to test here
}
}
if I want to set a return value for callMethodTwo, can I do that? I
was trying this:

myClassName = new myClassName();
myClassName.callMethodTwo(Arg.Do(functionhere));

this is causing an error because it's actually running callMethodTwo
with a null parameter.

How do I test myMethod() without making myClassName a substitute?

Brendan Forster

unread,
Jun 28, 2012, 7:05:43 PM6/28/12
to nsubs...@googlegroups.com
Not 100% sure I follow the question but I'll give it a crack.

You can create substitutes for concrete classes, but unless their access modifiers are NSubstitute-friendly you will not be able to override the original implementation.

Consider a class with two methods that you'd like to override when testing:

public class ConcreteClass
{
    public int RunSomething()
    {
        return SomeMethod();
    }

    public virtual int SomeMethod()
    {
        throw new NullReferenceException();
    }

    public int CannotOverride()
    {
        throw new InvalidOperationException();
    }
}

Note how one is virtual and the other isn't.

Because the first method uses the virtual keyword, NSubstitute can intercept calls to your original method at runtime:

        [Fact]
        public void RunSomething_WithInnerMethodOverriden_ReturnsOurValue()
        {
            var someObject = Substitute.For<ConcreteClass>();

            someObject.SomeMethod().Returns(-1);

            Assert.Equal(-1, someObject.RunSomething());
        }


Without that, you will invoke the original method if you attempt to mock it out:

        [Fact]
        public void CannotOverride_OtherMethod_AsItIsNotVirtual()
        {
            var someObject = Substitute.For<ConcreteClass>();

            Assert.Throws< InvalidOperationException>(() => someObject.CannotOverride().Returns(-1));
        }
    }

Hope that helps,
Brendan



--
You received this message because you are subscribed to the Google Groups "NSubstitute" group.
To post to this group, send email to nsubs...@googlegroups.com.
To unsubscribe from this group, send email to nsubstitute...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nsubstitute?hl=en.


David Tchepak

unread,
Jun 28, 2012, 7:24:16 PM6/28/12
to nsubs...@googlegroups.com
You can not use Arg.Do(...), or any Arg. methods, on non-substitutes
or on non-virtual methods (as Brendan pointed out). They tell
NSubstitute to do stuff internally, but externally they just return
null.

If you want to stub out the result of `callMethod` I'd normally
extract out a class (or Func) that handles the required behaviour and
substitute that.

public class MethodTwoEr {
public virtual string MethodTwo(object x) { ... }
}

public class myClassName {
MethodTwoEr a;
public myClassName(MethodTwoEr a) { this.a = a; }
public void myMethod() {
// stuff
var result = a.MethodTwo(variable);
// more stuff with result
}

[Test]
public void TestMyMethod() {
var sub = Substitute.For<MethodTwoEr>();
sub.MethodTwo("hello").Returns("World");
var myClass = new myClassName(sub);

myClass.myMethod();

//assert that myMethod used the return value form
MethodTwoEr.MethodTwo properly.
}

Does that help?

Cheers,
David

On Fri, Jun 29, 2012 at 12:02 AM, t_elsmore <elsmo...@gmail.com> wrote:

t_elsmore

unread,
Jun 29, 2012, 11:24:20 AM6/29/12
to nsubs...@googlegroups.com
David, your answer was correct, which I figured out a few hours after posting this originally. The reason Brendan's doesn't work for me is that I want to test a method inside ConcreteClass, so I dont' want to s substitute it.
 
Thanks
Reply all
Reply to author
Forward
0 new messages