Ayende @ Rahien

Oren Eini aka Ayende Rahien CEO of Hibernating Rhinos LTD, which develops RavenDB, a NoSQL Open Source Document Database.

You can reach me by:

oren@ravendb.net

+972 52-548-6969

Posts: 6,903 | Comments: 49,340

filter by tags archive
time to read 1 min | 170 words

There has been an invaluable amount of discussion regarding the question I pose about the API design of Rhino Mocks 3.5. Jeremy Gray in particular has been helpful in making good suggestions and making the argument to simplify the API for developers who are not experts in TDD terminology and usage.

My current thinking is to combine GenerateMock() and GenerateStub() into a single method, GenerateTestDouble(). This method will return a dynamic mock.

If you want a true stub, you will be able to call myTestDouble.StubUnexpectedInteractions(). Note, since stubs have a special behavior for properties, I am also considering: myTestDouble.StubPropertiesAndUnexpectedInteractions(); .

If you want a strict mock, you will be able to call myTestDouble.FailOnUnexpectedInteractions();

Partial mock will not be supported by the static GenerateTestDouble method, and will require using the usual instance methods.

Calling VerifyAllExpectations() will be supported on all mocks.

The only remaining open question is whatever calling Expect() on an object that you previously called StubUnexpectedInteractions() should fail or not.

Thoughts?

time to read 2 min | 235 words

Let us say that we have the following code that we want to test:

public void ForgotMyPassword(string username)
{
   var user = users.GetUserByName(username);
   user.HashedPassword = "new pass";
   users.Save(user);
}

One way to write the test is:

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();
}

Another would be:

public void When_user_forgot_password_should_reset_password()
{
    var stubUserRepository = MockRepository.GenerateStub<IUserRepository>();
    var stubbedSmsSender = MockRepository.GenerateStub<ISmsSender>();

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

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

    var controllerUnderTest = new LoginController(mockUserRepository, stubbedSmsSender);

    controllerUnderTest.ForgotMyPassword("ayende");

    stubUserRepository.AssertWasCalled( x => x.Save(user));
}

Again, we have the question of should we even allow asserts on stubs. But beyond that, consider this two tests, both are functionally the same. Thoughts?

time to read 1 min | 51 words

Here is an interesting problem. What should this piece of code do?

var stubSmsSender = MockRepository.GenerateStub<ISmsSender>();
// test code
stubSmsSender.VerifyAllExpectations();

Right now this is a no-op.

But since stubs are explicitly not mocks, they shouldn't be verified. Should I throw here? For something which is a test design decision?

FUTURE POSTS

  1. Searching through text: Part III, Managing posting lists - one day from now
  2. Creating a good SaaS experience in the cloud - about one day from now

There are posts all the way to Oct 18, 2019

RECENT SERIES

  1. Searching through text (3):
    16 Oct 2019 - Part II, Exploring posting lists persistence
  2. re (22):
    19 Aug 2019 - The Order of the JSON, AKA–irresponsible assumptions and blind spots
  3. Design exercise (6):
    01 Aug 2019 - Complex data aggregation with RavenDB
  4. Reviewing mimalloc (2):
    22 Jul 2019 - Part II
  5. Production postmortem (26):
    07 Jun 2019 - Printer out of paper and the RavenDB hang
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats