5

Forgive me if this is a stupid question, but I'm fairly new at mocking, and am trying to get my head around it.

I have some unit tests (using the built-in Visual Studio 2010 Professional testing features), which use a stub that is needed by a method. I created a stub, and set the default return values for a couple of properties and a method, and all works well. I have a static class that sets up the stub, and this is used in the TestInitialize method to set up the stub...

public static AppointmentReminderProviderInterface GetMockProvider() {
  AppointmentReminderProviderInterface provider = MockRepository.GenerateStub<AppointmentReminderProviderInterface>();
  provider.Stub(p => p.ContactName).Return(MockProviderContactName);
  provider.Stub(p => p.ContactEmail).Return(MockProviderContactEmail);
  return provider;
}

Note that MockProviderContactName and MockProviderContactEmail are local string properties that contain default data for the provider. The unit tsts that check to see if things work as expeced with the default data all pass fine.

However, I now want to test what happens when one of these properties contains duff data. I thought I could just set this on the stub, but it isn't working. The test method contains the following lines...

_provider.Stub(p => p.ContactEmail).Return("invalid");
Debug.WriteLine("Provider email: <" + _provider.ContactEmail + ">");

The Debug.WriteLine() shows me that, despite the fact that I have set the ContactEmail property to return "invalid" it still returns the default email address. This causes my test to fail, as I'm expecting it to throw an exception, and it doesn't.

Anyone any idea why I can't change the return value of this property?

Thanks for any help.

Alexander Stepaniuk
  • 6,217
  • 4
  • 31
  • 48
Avrohom Yisroel
  • 8,555
  • 8
  • 50
  • 106
  • 1
    I've never used Rhino Mocks but in other mocking frameworks I've used when you set a return value more than once, as in your case, the first value gets returned in the first method/property call, and the second value gets returned the second time you access that member (etc., etc. Also, the last value set is usually returned in further subsequent calls). – Allon Guralnek Dec 17 '12 at 17:42
  • Hi Allon, thanks for the reply. If your suggestion were correct, then the Debug.WriteLine call I showed should have output the "invalid" value, and then the test method itself should have been given the original value. However, I always seem to get the default value, irrespective of what I set by calling Stub() again. Thanks anyway. – Avrohom Yisroel Dec 17 '12 at 18:00
  • Redesign your tests so that you don't need to change stub return value during testing. You have to define return value only once. – Alexander Stepaniuk Dec 17 '12 at 20:26

2 Answers2

6

As a tricky but working solution I'd suggest to use Do handler here. It allows to implement some logic for stubbed method/property.

See example:

var providerContactEmail = "Email1";

provider
    .Stub(p => p.ContactEmail)
    .Do((Func<string>)(() => providerContactEmail));
// here provider.ContactEmail returns "Email1"

providerContactEmail = "Email2";
// now provider.ContactEmail returns "Email2"

But in my opinion it is much better if the solution can be found which allows to don't change return value in the middle of test. :)

Alexander Stepaniuk
  • 6,217
  • 4
  • 31
  • 48
1

Try changing

_provider.Stub(p => p.ContactEmail).Return("invalid");

To

_provider.ContactEmail = "invalid";

Assuming ContactEmail has a setter, this should work. If this doesn't resolve your issue, I'd follow Alexander Stepaniuk's advice and refactor your test so that you're not adding multiple behaviors for the same stub; I think that has something to do with your issue.

Adam Prescott
  • 943
  • 1
  • 8
  • 20
  • Hello, thanks for the reply. Unfortunately, ContactEmail doesn't have a setter, so short of some jiggery-pokery, I can't set it directly. I got around the problem temporarily by setting up a separate stub with the invalid email address, but I can see this being a huge pain as the number of combinations I want to test increases. I was hoping I could start with the one default stub, and just modify the properties I wanted at the start of the test. It looks like I'm going to end up with a huge amount of almost identical code in my tests. Surely I'm not the first person to face this issue? Thanks – Avrohom Yisroel Dec 18 '12 at 14:15
  • How about this: create a method that recreates the entire stub object with the specific values you need. This would allow you to use the default case for most tests and then create an entirely new provider when you need something other than the default. The other proposed answer, using the Do method, would probably accomplish the job, too. – Adam Prescott Dec 18 '12 at 20:05