When using IronRuby to test C# applications we are still faced with similar issues as with C# – the different is how we can handle them. For example, to stub the HttpRequestBase in C#, we could use Rhino Mocks as follows.
var stubbedHttpRequest = MockRepository.GenerateStub().Stub(x=>x.ApplicationPath).Return(“~/test”);
I do really like this syntax and think it works for C#. However, if we are looking to use Ruby and a dynamic language we have the potential to be more inventive.
IronRuby has an excellent framework called Caricature which allows you to fake CLR objects. For example, here we are stubbing the HttpRequestBase from MVC.
require 'caricature'
include Caricature
stubHttpRequest = isolate System::Web::HttpRequestBase
stubHttpRequest.when_receiving(:application_path).return("~/test")
stubHttpRequest
However, this got me thinking. With Ruby being dynamic, how could we take advantage when defining fakes? For example, what about the following syntax:
stubHttpRequest = stub 'System::Web::HttpRequestBase
.ApplicationPath.returns("~/test") &&
.FilePath.returns("")'
This would stub two properties, ApplicationPath and FilePath to return “~/test” and an empty string respectively. If we wanted to handle method calls and arguments, we could have the following:
stubHttpRequest = stub 'System::Web::HttpRequestBase
.SomeMethodCall("WithArgument").returns(SomeObject.new) &&
.SomeOtherMethod(*).returns(-1)'
Here we stub two methods, one stubs with a particular argument (must be the string “WithArgument”) while the other matches on any argument.
My aim is to reduce the ceremony associated with the act of stubbing and instead focus on the true intent of the defined behaviour.
Note: Imagine the ‘refactoring’ problem has been solved, and changing the method names would also update the tests.
If we look at other languages, for example Javascript’s jqMock and Ruby’s NotAMock are using a similar syntax to C#.
var alertMock = new jqMock.Mock(window, "alert");
alertMock.modify().args("hello world new!").returnValue();
I think it is time to start looking beyond the existing syntax and reveal our true intent. What do you think?