Oren Eini

CEO of RavenDB

a NoSQL Open Source Document Database

Get in touch with me:

[email protected] +972 52-548-6969

Posts: 7,527
|
Comments: 51,162
Privacy Policy · Terms
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 1 min | 156 words

Several months ago I wrote about how I think you should design your services. The key criteria was that they have to have a batch mode enabled.

Afterward, I put together a screen cast that goes through all the stages that led me to that stage.

Davy Brion has taken this approach a bit further and posted all the infrastructure bits that are required to make this work as well as what you need to actually make the API almost as nice to use as the non batched version.

The service API is here and the client API is here.

About the only thing that I would strive to improve there would be the need to explicitly register request & replies. I would try to get something convention based there. Maybe something like Request<TRespose>, and then have IHandler<TRequest> and route the whole thing through the container again.

time to read 1 min | 118 words

public class ARValidatingAuthorizationRepository<TIEntityType, TIUsersGroup, TIEntitiesGroup, TIOperation, TIEntityReference, TIPermission>     
  :  RhinoAuthorizationRepository< TIEntityType, TIUsersGroup, TIEntitiesGroup, TIOperation, TIEntityReference, TIPermission> 
      where TIEntityType : class, IEntityType, new()
      where TIUsersGroup : class, IUsersGroup, new()
      where TIEntitiesGroup : class, IEntitiesGroup, new()
      where TIOperation : class, IOperation, new()
      where TIEntityReference : class, IEntityReference, new()
      where TIPermission : class, IPermission, new()
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?

time to read 3 min | 448 words

Well, after a much longer beta period, and getting some very valuable input, Rhino Mocks 3.5 is out in Release Candidate. I am putting this out as RC, but I am pretty sure that those bits would be the RTM version as well.

The only major task left is to start documenting the changes. The move to 3.5 has made a lot changes in approach that I recommend to use (note that the API is compatible with 3.4).

I would like to thank Jordan Terrell, David Tchepak, Stefan Steinegger, Jason Meckley, Scott Brady, Ernst Naezer, Roelof Blom and Aaron Jensen for helping me get this out the door.

The changes (from 3.4) are:

  • Assert Act Arrange syntax, of course.
  • Better handling of exception in raising events from mock objects
  • Fixing an issue with mock objects that expose methods with output parameter of type System.IntPtr.
  • Allowing to return to record mode without losing expectations.
  • Inline constraints:
[Test]
public void WhenUserForgetPasswordWillSendNotification_WithConstraints()
{
    var userRepository = MockRepository.GenerateStub<IUserRepository>();
    var notificationSender = MockRepository.GenerateStub<INotificationSender>();

    userRepository.Stub(x => x.GetUserById(5)).Return(new User { Id = 5, Name = "ayende" });

    new LoginController(userRepository, notificationSender).ForgotMyPassword(5);

    notificationSender.AssertWasCalled(x => x.Send(Arg.Text.StartsWith("Changed") ));
}
  • CreateMock() is deprecated and marked with the [Obsolete] attribute. Use StrictMock() instead.
  • Fixed an issue with merging, would cause issues if you are also using Castle Dynamic Proxy.
  • Fixed various typos
  • Better error handling for AAA syntax abuse
  • Will give better errors if you call Verify on a mock that is in record mode.
  • BackToRecord extension method.
  • Can mock interfaces with modopt params.
    • If you don't know what this means, it means that you can now mock interfaces that C++/CLI generates under some conditions (mixing native types with CLR types). This is probably the longest standing bug in Rhino Mocks.
  • Fixed issue with mocking internal classes and interfaces.
  • Full XML documentation
  • New event raising syntax:
    eventHolder.Raise(stub => stub.Blah += null, this, EventArgs.Empty);
  • AAA syntax now works with Ordering
  • Better error message if trying to use SetupResult on stubbed mock properties.
  • There are a lot of goodies in this release.

    I am starting to create the documentation for this release here. This is a wiki, any help would be appreciated.

    You can get the new version, for both 3.5 and 2.0 from the download page.

    time to read 2 min | 372 words

    Some people pointed out that the distinction between public and published can be done using InternalsVisibleTo. This is sort of possible, I agree, but it only works if you think about this as a unit testing measure.

    Jon Skeet asked about good usages of InternalsVisibleTo aside from unit testing, and I decided to check and see what the framework is using it for. From cursory observation, it appears to be heavily misused. Just from observing the allowed dependencies make me cringe.

    • System.Data allows:
      • System.Data.Entity
      • SqlAccess
      • System.Data.DataSetExtensions
    • System.Web allows:
      • System.Web.Extensions
    • System.Xml allows:
      • System.Data.SqlXml
    • System.Data.SqlXml allows:
      • System.Xml <-- I don't want to know how they got this cycle
    • Microsoft.NETCF.Tools allows:
      • System.Web.Services <-- This one really scares me
    • Microsoft.Office.Tools.Common.v9.0 allows:
      • Microsoft.Office.Tools.Word.v9.0
      • Microsoft.VisualStudio.Tools.Office.Designer.Office2007
      • Microsoft.VisualStudio.Tools.Office.Designer.Office2007Tests
      • Microsoft.VisualStudio.Tools.Office.Outlook.UnitTests
    • Microsoft.Build.Conversion allows:
      • Microsoft.Build.Conversion.Unittest
    • Microsoft.Build.Engine allows:
      • Microsoft.Build.Engine.Unittest
    • PresentationCore allows:
      • System.Windows.Presentation
    • PresentationFramework allows:
      • PresentationFramework.Luna
    • System.Core allows:
      • Dlinq.Unittests <-- this is annoying, I don't get internals access to that, and I am also writing a linq provider
    • System.Design allows:
      • System.Web.Extensions.Design <-- well, if I want to write a designer, I have better work for MS...

    Git to CodePlex

    time to read 1 min | 113 words

    Well, it works, finally.

    image

    I had major issues getting commits to work. Eventually I figured out that git-svn does not send hashes of the files as all other SVN clients that I have tested so far. I was focused on finding corruption much earlier in the game, and drowned in the details.

    I am not sure why it is committing a single change twice, but it is showing the same behavior on standard SVN servers, so I think that I am fine.

    And here is the final test:

    image

    :-D

    FUTURE POSTS

    1. RavenDB Performance: 15% improvement in one line - 15 hours from now

    There are posts all the way to Dec 02, 2024

    RECENT SERIES

    1. RavenDB Cloud (2):
      26 Nov 2024 - Auto scaling
    2. Challenge (75):
      01 Jul 2024 - Efficient snapshotable state
    3. Recording (14):
      19 Jun 2024 - Building a Database Engine in C# & .NET
    4. re (33):
      28 May 2024 - Secure Drop protocol
    5. Meta Blog (2):
      23 Jan 2024 - I'm a JS Developer now
    View all series

    Syndication

    Main feed Feed Stats
    Comments feed   Comments Feed Stats
    }