Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Substitute read only property in partially mocked object

I'm testing an MVC controller which relies on a value returned from a read-only property on the base class.

The getter for this property throws an exception when it is called as it is relies on a HttpContext (and other nasty stuff) which I would rather avoid mocking.

This is what I've tried so far:

controller = Substitute.ForPartsOf<MyController>(
    Substitute.For<SomeDependency>(),
);

controller.UserInfo.Returns(new UserInfo());

Yet this throws an exception as soon as UserInfo is accessed.

Property on base class is:

public UserInfo UserInfo
{
    get
    {
        // HttpContext dependent stuff
    }
}

I've tried setting the base class property to virtual but then I get a Castle proxy exception.

like image 648
Ben Foster Avatar asked Apr 09 '14 09:04

Ben Foster


1 Answers

I think you may be having another problem. NSubstitute is capable of handling substitution of virtual properties. Here is a small program that illustrates

public class SubstitutedClass
{
    public virtual int SubstitutedProperty { get { throw new InvalidOperationException(); }  }
}

internal class Program
{
    private static void Main(string[] args)
    {
        var test2 = Substitute.For<SubstitutedClass>();
        test2.SubstitutedProperty.Returns(10);
        Console.WriteLine(test2.SubstitutedProperty);
    }
}

EDIT: Regarding your use of ForPartsOf I don't think it is possible to override a property this way, since there is no way of informing NSubstitute that we don't want it to call the base code. That's why the documentation mentions that partial sub are not recommended

You could change the base class in order to return the value of a virtual function; this virtual function would then be substituted. No signature change for the callers. Although this is a hack you would get what you need

public class SubstitutedClass
{
    public virtual int SubstitutedProperty { get { return InnerValue(); } }
    public virtual int InnerValue() { throw new InvalidOperationException(); }
}

var test2 = Substitute.ForPartsOf<SubstitutedClass>();
test2.When(t => t.InnerValue()).DoNotCallBase();
test2.InnerValue().Returns(10);
like image 106
samy Avatar answered Oct 24 '22 19:10

samy