I'm having a hard time understanding if I've got the right approach here. I want to test a repository. The repository is dependent on a DbContext. I want to be able to verify that the repository did not call a function Add on a property of type IDbSet which is a member of the DbContext.
I've tried two approaches. Verify with behaviour, and verify with state. Seems that verify with behaviour would be right because who knows what the stubbed state is doing in a fake object.
public void VerifyBehaviour()
{
// Arrange
var stubEntities = MockRepository.GenerateStub<IWsStatContext>();
var stubManufcturers = MockRepository.GenerateStub<IDbSet<Manufacturer>>();
var manufacturer = new Manufacturer() { Name = "Dummy" };
var manufacturers = new List<Manufacturer>();
manufacturers.Add(manufacturer);
stubManufcturers.Stub(x => x.Local).Return(new System.Collections.ObjectModel.ObservableCollection<Manufacturer>(manufacturers));
stubManufcturers.Stub(x => x.SingleOrDefault(m => m.Name == "Dummy")).Return(manufacturer);
stubEntities.Manufacturers = stubManufcturers;
// Act
var sut = new EquiptmentRepository(stubEntities);
sut.AddManufacturer(manufacturer);
// Assert
stubManufcturers.AssertWasNotCalled(x => x.Add(manufacturer));
}
public void VerifyState()
{
// Arrange
var stubEntities = MockRepository.GenerateStub<IWsStatContext>();
var stubManufacturers = new InMemoryDbSet<Manufacturer>();
var manufacturer = new Manufacturer() { Name = "Dummy" };
stubManufacturers.Add(manufacturer);
stubEntities.Manufacturers = stubManufacturers;
// Act
var sut = new EquiptmentRepository(stubEntities);
sut.AddManufacturer(manufacturer);
// Assert
Assert.AreEqual(stubManufacturers.Count(), 1);
}
Verify behaviour approach fails with NullReferenceExceptions around the stub of SingleOrDefault. So I find posts saying best to verify state and use a fake DbSet. But it feels wrong to be checking state of a fake object. What if the Add function was implemented differently than the real one (which it was originally and my test was passing even though my repository was broken).
Does anyone know how to stub the SingleOrDefault so I can check Add was called? I can't check Add was called on a non-rhinomocked stub.
Thanks
As stated in jimmy_keen's answer:
SingleOrDefaultis an extension method defined onIEnumerable<T>(whichIDbSet<T>implements). Being extension method means it is a static method. RhinoMocks (or any other free tool) cannot mock/stub static methods.
Rather than trying to 'stub' the extension method, try stubbing the underlying interface that the extension method is built upon: IEnumerable<T>
stubManufcturers.Stub( x => x.GetEnumerator() ).Return( new List<Manufacturer> { manufacturer }.GetEnumerator() );
By stubbing the behavior of GetEnumerator() when SingleOrDefault is called it will execute as expected against the fake enumeration and the test will be able to evaluate the behavior.
SingleOrDefault is an extension method defined on IEnumerable<T> (which IDbSet<T> implements). Being extension method means it is a static method. RhinoMocks (or any other free tool) cannot mock/stub static methods.
Unfortunatelly you don't have many options here: you'll either have to do state-based verification, or create hand made mock and set it up manually for your test (but this most likely will end up with state-based verification as once again - you can't really stub SingleOrDefault).
Edit: extract and override example:
Firstly, you need to extract problematic part of your class to separate method that will be later overridden. This problematic part is naturally interaction with IDbSet:
public class EquiptmentRepository
{
public void Add(Manufacturer m)
{
// perform some local logic before calling IDbSet.Add
this.AddToDbSet(m);
}
protected virtual AddToDbSet(Manufacturer m)
{
this.context.Manfuacturers.Add(m);
}
}
Now, in your testable version of EquiptmentRepository you override AddToDbSet to make testing easier, for example by simply adding some state verification:
internal void TestableEquiptmentRepository: EquiptmentRepository
{
internal List<Manufacturer> AddedManufacturers = new List<Manufacturer>();
protected override void AddToDbSet(Manufacturer m)
{
// we're no longer calling DbSet.Add but kind of rolling
// our own basic mock and tracking what objects were
// add by simply adding them to internal list
this.AddedManufacturers.Add(m);
}
}
Whenever Add is called, passed manufacturer is going to be add to list if it would be added to DbSet in real case. In your test, you can simply verify your testable version of the class state:
[Test]
public void AddManufacturer_DoesNotAddExistingManufacturersToDbSet()
{
// Arrange
var stubEntities = MockRepository.GenerateStub<IWsStatContext>();
var stubManufacturers = MockRepository.GenerateStub<IDbSet<Manufacturer>>();
var manufacturer = new Manufacturer() { Name = "Dummy" };
stubManufacturers.Add(manufacturer);
stubEntities.Manufacturers = stubManufacturers;
// Act
var sut = new TestableEquiptmentRepository(stubEntities);
sut.AddManufacturer(manufacturer);
// Assert
Assert.AreEqual(sut.AddedManufacturers.Count(), 0);
}
This way you can verify all the logic in EquiptmentRepository.Add without the need to interact with DbSet at all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With