tags:

views:

36

answers:

3

Hi I am trying to test a property that is nested in a child class. I always get an error. Am I missing something? Is it possible to test a child property in moq.

I have the following

     [Test]
public void Should_be_able_to_test_orderCollection()
    {
        var orderViewMock = new Mock<IOrderView>();
        orderViewMock.SetupGet(o => o.Customer.OrderDataCollection.Count).Returns(2);          

        orderViewMock.SetupSet(o => o.Customer.OrderDataCollection[1].OrderId = 1);

        orderViewMock.VerifySet(o => o.Customer.OrderDataCollection[1].OrderId=1);
    }

    public class CustomerTestHelper
    {
        public static CustomerInfo GetCustomer()
        {
            return new CustomerInfo
           {
               OrderDataCollection = new OrderCollection
                 {
                     new Order {OrderId = 1},
                     new Order {OrderId = 2}
                 }
           };

        }
    }
    public class CustomerInfo
    {
        public OrderCollection OrderDataCollection { get; set; }
    }

    public class OrderCollection:List<Order>
    {
    }

    public class Order
    {
        public int OrderId { get; set; }
    }
    public interface  IOrderView
    {
        CustomerInfo Customer { get; set; }
    }
+1  A: 

It is definitely possible if you have the right abstractions. You need to mock your Customer and its children too, for your example to work, like:

var customerMock = new Mock<ICustomer>();
orderViewMock.SetupGet(o => o.Customer).Returns(customerMock.Object);

etc. for the entire hierarchy of child objects you want to control with mocks. Hope it makes sense.

/Klaus

klausbyskov
Thanks for your reply.Still cannot get the collection.Count workingI would like to verify the mock.Customer.OrderCollection.Count=2is this possible?
orderViewMock.SetupGet(o => o.Customer.OrderCollection).Returns(orderViewMock.Object.Customer.OrderCollection); The above is what I tried
No, as @Mark Seemann stated above, you can only mock abstract classes and interfaces, so you need to abstract the `OrderCollection` aswell for that to work.
klausbyskov
@devnet247 - you'll need to have your ICustomer return an IOrderCollection (or ICollection, etc.), probably of IOrder instances. Alternately, see http://en.wikipedia.org/wiki/Law_of_Demeter
TrueWill
+1  A: 

You can't mock the OrderDataCollection property of CustomerInfo because it's a non-virtual property on a concrete class.

The best way to fix this would be to extract an interface from CustomerInfo and let IOrderView return that instead:

public interface IOrderView
{
    ICustomerInfo Customer { get; set; }
}
Mark Seemann
Thanks for your reply.Are you saying that I should make that property virtual and it will work?
Making OrderDataCollection virtual might work as well. On another note, collection properties ought to be read-only.
Mark Seemann
Thanks a lot I seems to understand it now.I made an Interface
A: 

You will get a runtime error, as you've found:

System.ArgumentException: Invalid setup on a non-overridable member:
o => o.Customer.OrderDataCollection.Count
at Moq.Mock.ThrowIfCantOverride(Expression setup, MethodInfo methodInfo)

You can mock the IOrderView and return any CustomerInfo instance you want, but you're also trying to mock CustomerInfo and OrderCollection. As Mark Seemann mentioned, you can only mock interfaces and virtual properties/methods. This will hold true for almost any mocking/isolation framework except for Typemock (commercial).

As others have already stated, one way to solve the problem is to return an interface for the customer.

TrueWill