0

I am pretty familiar with unit testing and do understand the difference between mocks and stubs. The simplest explanation from Roy Osherove is that all fakes start out as stubs until you assert against them, then they are mocks.

Again, I get all that. My question is "Is it wrong to use a single fake instance as both a mock and a stub? Take the following example from the Rhino Mocks documentation (http://ayende.com/wiki/Rhino+Mocks+3.5.ashx)

public void When_user_forgot_password_should_save_user()
{
  var mockUserRepository = MockRepository.GenerateMock<IUserRepository>();
  var stubbedSmsSender = MockRepository.GenerateStub<ISmsSender>();

  var theUser = new User{HashedPassword = "this is not hashed password"};    

  mockUserRepository.Stub(x => x.GetUserByName("ayende")).Return(theUser);

  mockUserRepository.Expect( x => x.Save(theUser) );

  var controllerUnderTest = new LoginController(mockUserRepository, stubbedSmsSender);

  controllerUnderTest.ForgotMyPassword("ayende");

  mockUserRepository.VerifyAllExpectations();
}

You'll notice that the mockUserRepository is named with the word mock and is calling the GenerateMock factory because further down in the code the mockUserRepository has a behavioral expectation established for it and eventually that expectation of behavior is being verified. Great, but along the way the mockUserRepository is calling its Stub() method to "can" the data returned by calls to GetUserByName() on the same object.

Clearly, this example shows using an explicitly named and declared mock as both a mock and a stub. Going back to Roy Osherove's definition that all fakes are stubs until you assert against them, I am forced to believe that using a fake as both a mock and a stub (while certainly works) is bad practice.

Does anyone know if there is a verdict on doing this?

Scott Marcus
  • 64,069
  • 6
  • 49
  • 71

1 Answers1

0

I really, really don't follow your logic. If every mock is a stub, and you agree with that, how can it be wrong to use a single instance as a mock and as a stub. You don't have a choice: a mock is a stub. And every time you use it as a mock, you also use it as a stub. To be able to verify that a mock has been called, the mock must have been called. If it has been called, it must have done something when called (i.e. return a specific value of throw an exception). And to be able to make it return something, you must have stubbed it.

BTW, most of the time, a component under test uses one instance of a given collaborator, not two. So obviously, you need to stub that instance. And to verify interactions on this instance, the stub must become a mock. So you must use it as both a mock and a stub.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • I don't agree that every mock is a stub, nor is that what I said. I said that every "fake" starts out as a stub and, depending how you use it, it may turn out to be a mock instead. What this simply means is that we need to create a fake object for 2 possible reasons (fake input to the method under test or fake interaction with an external system), but unless we assert against the fake, the fake falls under the category of a stub. The only time your fake can accurately be called a mock is if you assert against it. – Scott Marcus Sep 20 '15 at 19:02
  • That's not the main point. Suppose some code does `int i = foo.getValue(); foo.setValue(i * 2);`. If you want to test this method, you'll need to stub foo so that getValue() returns some integer, 5 for example. To ensure it calls foo.setValue() with 10, as it's supposed to do, you'll need to verify that foo.setValue() has been called with 10, and thus use the stub as a mock. You don't have a choice. The code doesn't use 2 different foos. It uses just one. So, the stub also needs to be a mock. – JB Nizet Sep 20 '15 at 19:09
  • Yes, but those would be two different tests and thus in one test, I'd need to stub foo.getValue() so that it would return the canned data that my method under test expects and I'd assert against my method under test. And, in another test, I'd need to mock foo.setValue() and assert that it was called. There shouldn't be one test to handle both scenarios. – Scott Marcus Sep 20 '15 at 19:14
  • How could you write the second test without stubbing foo.getValue()? What will be your assertion? Try doing it. A stub isn't used to verify that something returns an expected value. A stub is used to make an method return what you want it to return. And there is a single scenario here, not two. We're talking about a single method with these two instructions. – JB Nizet Sep 20 '15 at 19:17
  • I see your point, which really just brings me back to my original question relating to the Rhino Mocks documentation (and perhaps is really just a disagreement with the nomenclature of Rhino), which is that if i create a new Mock, it seems incorrect to call its Stub() method. I guess it would have been better for Rhino to have one "fake" instance named as such that you could then use as a stub or a mock and your usage would dictate what it was. – Scott Marcus Sep 20 '15 at 19:56
  • I don't know anything about Rhino Mocks, but I don't see why it would be incorrect. A mock is also a stub. So clling stub on a mock is OK. The reverse is not true. A stub is not a mock, so, as the documentation says about stubs: "expectations will never be verified". – JB Nizet Sep 20 '15 at 20:02
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/90175/discussion-between-user1739635-and-jb-nizet). – Scott Marcus Sep 20 '15 at 20:34
  • Mocks are not stubs and stubs are not mocks. Both are forms of fake objects, but there is a very distinct difference between the two. See: http://martinfowler.com/articles/mocksArentStubs.html for more information. This point is really the basis of my question. – Scott Marcus Oct 14 '15 at 20:04