Occurs(n) overrides behavior of Throws()?

2 posts, 0 answers
  1. James Legan
    James Legan avatar
    54 posts
    Member since:
    Sep 2008

    Posted 18 Sep 2012 Link to this post

    I have a unit test that has two calls to SaveChanges() when the first attempt to call SaveChanges() throws an OptimisticVerificationException, a refresh of the object occurs and then a second attempt is made. When writing my unit test I arranged the following expectations:

    Mock.Arrange(() => _mockModel.SaveChanges()).Occurs(2);
     
    Mock.Arrange(() => _mockModel.SaveChanges()).Throws<OptimisticVerificationException>(string.Empty).InSequence();
     
    Mock.Arrange(() => _mockModel.SaveChanges()).InSequence();
     
    Mock.Arrange(() => _mockModel.Users.SingleOrDefault(p => p.Guid == userGuid)).Returns(new User());
     
    Mock.Arrange(() => _mockModel.Refresh(RefreshMode.OverwriteChangesFromStore, Arg.IsAny<User>())).MustBeCalled();

    What is interesting is that the call to: Mock.Arrange(() => _mockModel.SaveChanges()).Occurs(2); actually breaks the next two lines (the one that throws on the first SaveChanges() in sequence). Regardless of where Occurs(n) appears in the arrange, it breaks the throw. Simply commenting it out allows the test to run as expected.

    Am I doing something wrong or is there a defect here?

  2. Ricky
    Admin
    Ricky avatar
    467 posts

    Posted 21 Sep 2012 Link to this post

    Hi James,

    I wrote a simple test to reproduce your problem and found out that if you write it in the following way then it works as expected. Since, you have specified InSequence in the Throws setup, it will make the previous setup first in order. However, by default the behavior is override (similar to other mocking tools). So If you do the following then it will work as expected:

     

    Mock.Arrange(() => foo.SaveChanges()).Occurs(2);
    Mock.Arrange(() => foo.SaveChanges()).Throws<ArgumentException>();
    Mock.Arrange(() => foo.SaveChanges()).InSequence();

    Ideally you have to write the test in the following way to cover both the cases:

    [TestMethod]
    public void ShouldAssertThrowsOnFirstCall()
    {
        var foo = Mock.Create<IFoo>();
     
        Mock.Arrange(() => foo.SaveChanges()).Throws<ArgumentException>();
        Mock.Arrange(() => foo.SaveChanges()).InSequence();
     
        try
        {
            foo.SaveChanges();
            Assert.Fail("Must throw an exception");
        }
        catch (ArgumentException ex)
        {
     
        }
     
        foo.SaveChanges();
     
     
        Mock.Assert(() => foo.SaveChanges(), Occurs.Exactly(2));
    }
     
    public interface IFoo
    {
        void SaveChanges();
    }


    Kind Regards
    Mehfuz
    the Telerik team

    Time to cast your vote for Telerik! Tell DevPro Connections and Windows IT Pro why Telerik is your choice. Telerik is nominated in a total of 25 categories.

  3. DevCraft R3 2016 release webinar banner
Back to Top