0

I'm using the AAA-pattern and Rhino mocks for my unit-testing. I want to assert that a specific value (e-mail) has been set on an entity before I call SaveChanges() on DbContext. I have a test-method which looks like this:

protected override void Arrange()
{
    base.Arrange();
    _itemToUpdate = new FooEntity();
}

protected override void Act()
{
    base.Act();
    _resultEntity = Repository.Update(_itemToUpdate);
}

[TestMethod]
public void ShouldAssignEmailBeforeSave() // Act
{
   Context.AssertWasCalled(x => x.SaveChanges(), 
      options => options.WhenCalled(y => 
         Assert.IsTrue(_resultEntity.Email == "somevalue")));
}

But I'm realizing that the "WhenCalled"-method isn't executing, because I've also tried this:

[TestMethod]
public void ShouldAssignEmailBeforeSave()
{
    Context.Expect(x => x.SaveChanges())
       .WhenCalled(y => Assert.IsTrue(false));
}

I have also tried this syntax:

[TestMethod]
public void ShouldAssignEmailBeforeSave()
{
    Context.AssertWasCalled(x => x.SaveChanges(),
       options => options.WhenCalled(z => Assert.IsTrue(false)));
}

Both asserts above passes, which makes it obvious that I'm not using the WhenCalled correctly. Context is a mocked object of my DBSet. I've left the Arrange and the Act outside of the question for now because they seem to do what they should. It's the Assert that's not working.

How do I verify that a property is set on an entity before a method was called? In other words, how do I assert that something happened in a specific order?

  1. Set property.
  2. SaveChanges.

EDIT:

The "error" occurs because the Assert is done after the Act, which is correct. It's not possible to use WhenCalled in the Assert because the Act already happened. In this particular case the WhenCalled will never be invoked since the delegate is created after SaveChanges was invoked and thus didn't exist when called.

The alternative is to use Expect in the Arrange:

protected override void Arrange()
{
    base.Arrange();
    _itemToUpdate = new FooEntity();
    Context.Expect(x => x.SaveChanges()).Return(0).WhenCalled(y =>
    {
        Assert.IsTrue(false);
    });
}

[TestMethod]
public void ShouldCallSaveChanges()
{
    Context.VerifyAllExpectations();
}

But then you have an assert in the Arrange, which I believe goes against best practices of the AAA pattern. Any idéas for a better solution?

smoksnes
  • 10,509
  • 4
  • 49
  • 74
  • It's not clear to me from the question what is the tested object, what is the mocked object and what is the problem... If "SaveChanges" method is part of the mock, and you're expecting your tested object to call it, there's no issue in using "AssertWasCalled". Just not clear how's the e-mail value related? – Amittai Shapira Feb 07 '16 at 12:47
  • The Context in my case is an abstraction of DbContext from EntityFramework (and a mock). _resultEntity is the entity i want to update, using the context. I want to assure that the email address has been assigned to the entity before Context.SaveChanges() are called. – smoksnes Feb 08 '16 at 06:35
  • So you want to verify 2 items: 1. e-mail address was set 2. SaveChanges() was called. Why do you need to couple them? can't you have just two asserts (one on the property setter and another on the method call)? – Amittai Shapira Feb 08 '16 at 12:21
  • Yes, I want to make two asserts. But I want to make sure that they are done in that specific order. The property may not be called before SaveChanges(), because then the update will not write the correct changes. – smoksnes Feb 08 '16 at 12:23
  • Why not 2 calls: 1. Context.AssertWasCalled(x => x.SaveChanges()). 2. Assert.IsTrue(_resultEntity.Email == "somevalue")); – Amittai Shapira Feb 08 '16 at 12:55
  • Thank you for your suggestion, but what I'm trying to test is that the property-setter is called before the method SaveChanges(). Not that they have been called at all. It's the order that's important. – smoksnes Feb 08 '16 at 12:58
  • Thanks to your comments I realized that it wasn't clear what I wanted to do. I've adjusted the question a bit to make it a bit more clear. – smoksnes Feb 08 '16 at 14:36

2 Answers2

0

It seems what you're looking for is to verify the order of your mock calls. This was possible was MockRepository.Ordered() method of version 3.5, but is not part of 3.6 syntax.
You can see here and here possible solutions. This one is probably the simplest for AAA:

Context.AssertWasCalled(x => _resultEntity.Email = "somevalue", options => options.WhenCalled(w => Context.AssertWasNotCalled(x=>x.SaveChanges())));
Context.AssertWasCalled(x=>x.SaveChanges());
Community
  • 1
  • 1
Amittai Shapira
  • 3,749
  • 1
  • 30
  • 54
0

I ended up with this:

private FooEntity _itemToUpdate;
private FooEntity _resultEntity;

protected override void Arrange()
{
    base.Arrange();
    var correctValue = "somevalue"
    _itemToUpdate = new FooEntity()
    _itemToUpdate.Email = correctValue;

    // Context is a mock of a DbContext and inherited from base class.
    Context.Expect(x => x.SaveChanges()).Return(0).WhenCalled(y =>
    {
        Assert.AreEqual(_resultEntity.Email, correctValue);
    });
    Context.Replay();
}

protected override void Act()
{
    base.Act();
    // Repository is a mock of a repository and inherited from base class.
    _resultEntity = Repository.Update(_itemToUpdate);
}

[TestMethod]
public void ShouldAssignEmailBeforeSave() // Assert
{
   Context.VerifyAllExpectations();
}

Since the entity isn't a mock AssertWasCalled won't work.

smoksnes
  • 10,509
  • 4
  • 49
  • 74