chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
0 votes
I'm trying to isolate a class to test. This class has a couple of properties:

SortedList<string, string> Title
SortedList<string, string> Body

and an instance method:

bool Save(int id)

My test is as follows:

[Test]
[ExpectedException(typeof(PageCreationException))]
public void TestSaveThrows()
{
Mock page = MockManager.Mock<Page>();
page.ExpectAndReturn("Save", false);

PageHelper.CreatePage("title", "body");
}

in PageHelper:

public bool CreatePage(string title, string body)
{
Page p = new Page();
p.Title.Add("en", title);
p.Body.Add("en", body);
if (!page.Save())
{
throw new PageCreationException("Save borked");
}
}

When I try to do this, the properties Title and Body are null, even though they're correctly assigned in the Page class upon instantiation.

What's going on here? How do I isolate this method so that Save is faked and never called?
asked by scalvert (1.2k points)

4 Answers

0 votes
Hi,

If you want to the constructor of the Page object to be called, you need to explicitly say so, since the default is to mock the constructor.

Mock<Page> page = MockManager.Mock<Page>(Constructor.NotMocked); 


Hope that helps.
answered by gilz (14.5k points)
0 votes
OK, so I've changed my approach a bit and figured out a few things.

Here is my new test, using Natural Mocks instead of Reflective:

        [Test]
        [ExpectedException(typeof (CreatePageException))]
        public void CreatePageWith3ParamsThrowsIfCreationFails()
        {
            Page page = RecorderManager.CreateMockedObject<Page>(Constructor.NotMocked);
            User admin = this.Administrator; // property in my fixture
            using (RecordExpectations recorder = RecorderManager.StartRecording())
            {
                recorder.ExpectAndReturn(Profiles.IsUserAnAdministrator(admin), true);
                recorder.ExpectAndReturn(page.Save(admin.UserId), false);
            }

            this.Facade.CreatePage("My test page", "My body (sexy isn't it?)", admin);
        }


And here is my method under test:

        public int CreatePage(int parentId, string title, string body, User requestingUser)
        {
            Page createdPage = (Page) PageFactory.CreatePage(ContentType.Detail);
            createdPage.ParentId = parentId;
            createdPage.CreatorId = requestingUser.UserId;
            createdPage.OwnerId = requestingUser.OwnerId;
            createdPage.IsPublished = ContentRepository.Instance.GetContent(parentId, requestingUser).IsPublished;
            createdPage.Title.Add("en", title);
            createdPage.Body.Add("en", body);

            if (!createdPage.Save(requestingUser.UserId))
            {
                throw new CreatePageException("A problem occurred during the creation of your page.");
            }

            return createdPage.ContentId;
        }


When I run the test I get the following exception:

TypeMock.VerifyException:
TypeMock Verification: Method OpenRoad.ThoughtFarmer.Core.DetailPage.Save() has 1 more expected calls

I'm not sure I understand this message. If I debug the test, the call to CreatePage does call Page.Save, so I'm not clear what the exception message suggests.

Please advise.
answered by scalvert (1.2k points)
0 votes
Hi
It seems that the problem is because you are not setting the expectation for
the Save method for the right instance.

What happens is that you are creating an instance of Page using
MockManger.CreateMockedObject
Than you make an expectation on this object here:
recorder.ExpectAndReturn(page.Save(admin.UserId), false);


Than in code under test you create a different instance:
Page createdPage = (Page) PageFactory.CreatePage(ContentType.Detail);


So the expectation for Save is never fulfilled.

To fix that you can mock the factory method PageFactory.CreatePage to return the mocked object you created.
So the test look like this:
[Test]
[ExpectedException(typeof (CreatePageException))]
public void CreatePageWith3ParamsThrowsIfCreationFails()
{
   Page page = RecorderManager.CreateMockedObject<Page>(Constructor.NotMocked);
   User admin = this.Administrator; // property in my fixture
   using (RecordExpectations recorder = RecorderManager.StartRecording())
   {
      recorder.ExpectAndReturn(PageFactory.CreatePage(null), page);
      recorder.ExpectAndReturn(Profiles.IsUserAnAdministrator(admin), true);
      recorder.ExpectAndReturn(page.Save(admin.UserId), false);
   }

   this.Facade.CreatePage("My test page", "My body (sexy isn't it?)", admin);
}


This way the Factory method will return the mocked object which you set the expectation on.

:arrow: You can read the following post in our blog which explain the difference between Mock and MockObject.
You're not the only one who got confused by it :)
answered by ohad (35.4k points)
0 votes
Awesome. Worked perfectly. Thanks!
answered by scalvert (1.2k points)
...