views:

23

answers:

1

I'm trying to define a return value for a Mock (model).

Can anyone explain to me why the following code fails with a "Invalid setup on a non-overridable member":

model.SetupGet(x => x.PostCodeSearch).Returns(It.IsAny<string>);

and yet I can do this and it works fine:

model.Object.PostCodeSearch = "Any value as long as it's not null or empty";

The error message is clear enough but it seems strange that I can then apply values to properties directly on the Object property. What's the point of SetUpGet if I can do the latter?

+1  A: 

Make sure that PostCodeSearch is declared virtual on the faked types.

public virtual string PostCodeSearch { get; set; }

moq can fake only properties which are overridable.

Edit: dealing with non overridables

If the faked type cannot be changed there are different alternatives:

Change the production code to use a wrapper of the faked class. The wrapper will have the same API as the wrapped class, and all it'll do is route the calls to the wrapped object. The wrapper will declare the methods and properties as virtual. This way you get same behavior in the code with little change.

For example, if the original class being faked is MyClass:

public class MyClassWrapper
{
    MyClass myClass;

    MyClassWrapper(MyClass myClass)
    {
        this.myClass = myClass;
    }

    public virtual string PostCodeSearch
    {
        get { return myClass.PostCodeSearch; }
        set { myClass.PostCodeSearch = value; };
    }
}

The production code will use the MyClassWrapper instead of MyClass and it'll make the code testable using this little change.

Another alternative is to use an Isolation framework. Isolation frameworks enable faking of non-overridable members, static members, sealed classes...

For example, using Typemock Isolator:

MyClass myClass = new MyClass();
Isolate.WhenCalled(() => myClass.PostCodeSearch).WillReturn("faked value");

In this example the faked behavior is being set directly on the original class. The advantage here is that no change is required in the production code in order to make it testable.

Disclaimer - I work at Typemock

Elisha
Ok but when I don't have access to the source my use of the .Object is therefore valid?
Daz Lewis
@Daz Lewis, it's a bit more interesting case, updated answer
Elisha