Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I unit test protected properties meant to be set only by NHibernate?

I'm using NHibernate to persist this entity:

public class Store
{
    public int Id { get; protected set; }
    public int Name { get; set; }
}

Note how the Id property has a protected setter. This is to prevent users from changing the Id while still allowing NHibernate to assign it an Id when it saves it to the database.

In one of my unit tests, I'm using Moq with the following code to mock out my repository:

var mock = new Mock<IRepository>();
mock.Setup(x => x.GetById<Store>(It.IsAny<int>()))
    .Returns(new Store { Value = "Walmart" }); // can't set the ID here

var store = Repository.GetById<Store>(5);
Assert.That(store.Id == 5);

When I tell Moq to return a new Store instance, I can't assign the ID, and the unit test fails. How do I unit test this property? I don't want to change the access level of the property because I don't want users to change it manually, and yet that's exactly what I have to do here in order to test it.

like image 661
Daniel T. Avatar asked Sep 24 '10 03:09

Daniel T.


2 Answers

If you're not actually testing the Store class, then mock it, and use the SetupGet method:

var mock = new Mock<IRepository>();
var mockStore = new Mock<Store>();
mock.Setup(x => x.GetById<Store>(It.IsAny<int>())).Returns(mockStore.Object);

mockStore.SetupGet(s => s.Id).Returns(5);
mockStore.SetupGet(s => s.Value).Returns("Walmart");

var store = Repository.GetById<Store>(5);
Assert.That(store.Id == 5);
like image 148
Matt Mills Avatar answered Sep 22 '22 02:09

Matt Mills


In the test project create a child class of Store that allows for customization of the protected properties.

class TestableStore : Store { 
  public int TestableId { 
    get { return Id; }
    set { Id = value; }
  }
}

Then setup your unit tests to use return this instance when you need to construct a Store object.

mock
  .Setup(x => x.GetById<Store>(It.IsAny<int>()))
  .Returns(new TestableStore { Value = "Walmart", TestableId=42 }); 
like image 24
JaredPar Avatar answered Sep 20 '22 02:09

JaredPar