Oren Eini

CEO of RavenDB

a NoSQL Open Source Document Database

Get in touch with me:

oren@ravendb.net +972 52-548-6969

Posts: 7,585
|
Comments: 51,218
Privacy Policy · Terms
filter by tags archive
time to read 2 min | 379 words

That is how I built Rhino Mock 2.0.

I've a general idea about how I want it to look like, and I knew that I didn't like the current implementation. I wasn't very sure about how to go about implementing this, however. After my experiances with NQA, and after reading Working Effectively With Legacy Code, I knew that Test First is the way to go. So I started writing tests, and writing code to make them pass.

The part that I had a problem with was that I wrote code that I knew I was going to throw in a couple of hours / days, nevertheless, the tests require that it would give a complete solution to the problem. Then I added more functionality and I needed to rip apart the guts of the engine once more, and tottaly turn it around (from one mock at a time to managing several mocks at the same time.). Because I had the tests there, it took very little time to get back to where I was, and I'd the ground work to write more complicated tests.

Rhino Mocks 2.0 is feature complete starting from about 10 minutes ago, and all that remains is to switch NQA to the new version so I can dog food it properly. I expect to release it sometimes tonight. Here are some interesting statistics:

Total lines of code: 15,071 (Project) & 2,770 (Tests) = 17,841. Doesn't look too good, does it :-)

But: lines of code in the project, excluding generated strongly typed collections and xml comments: 1952 (Project) & 2382 (Tests)

So I actually have more code in the tests than in the code itself, which is what Test First should gives me. That was a very interesting experiment, btw, and quite a bit of fun.

"Your fault, core dumped." -- Tech Support Slogan
"IBM: Itty Bitty Mouse" -- Tech Support Slogan
"Out of my mind. Back in five minutes." -- Bumper Sticker

[Listening to: Jerusalem of Gold - Ofra Haza - Greatest Hits (disk 3)(05:47)]
time to read 2 min | 216 words

Just when I need the mailing list, SourceForge seems to be down :-( Correction, not down, just slow as hellllll!!! What is worse, it doesn't sends the confirmations emails for goinging mailing lists!

Anyway, I encountered very strange stuff going on in DynamicProxy, I'm currently adding support for mocking classes in Rhino Mocks, and I found that DynamicProxy can create proxies for:

  • Interfaces
  • Concrete classes
  • Abstract classes that has no abstract methods

But it can't create proxies for:

  • Sealed classes - this is reasonable.
  • Abstract classes that has abstract methods - I just can't understand this. What is the difference between that and an interface? Or proxing a class' virtual method? This seems completely arbitary to me.

As I said, I can't access the SourceForge mailing lists right now, so I can't ask the DynamicProxy team, anyone has an opnion why this is?

TDD Goodness

time to read 1 min | 184 words

I just had a complete surprise writing a test for Rhino Mocks. I'm doing that completely Test First, and I wrote a test, expecting it to fail. But it passed. Apperantly I'm already covering this case. :-)

This is so nice.

[Update: (five minutes later) Now it begins to be scary. I just wrote another test, for a part that I knew should be hard to get working. And it passed as well. The code handles it just fine, even though I thought I would need extensive changes to get it to work. I'm talking about ~1,300 LOC, and it still manages to surpirse the hell out of me.]

"E Pluribus UNIX." -- Tech Support Slogan
"If I had my life to live over again, I'd make the same mistakes, only sooner." -- tallulah bankhead
"The world is coming to an end... SAVE YOUR BUFFERS!!" -- Tech Support Slogan

[Listening to: Michal Amdursky - Pillow Talk - - (03:53)]
time to read 1 min | 151 words

I just got this error from the compiler:

The type or namespace name 'ILiar' could not be found (are you missing a using directive or an assembly reference?)

I was trying to type IList, and moved one key column to the left :-) I would worry about working on a project that had an ILiar interface.

"Not tonight dear.... I have a modem." -- Tech Support Slogan
"To punish me for my contempt for authority, fate made me an authority myself." -- Albert Einstein
"Never write software that patronizes the user." -- Tech Support Slogan

About Monad

time to read 2 min | 389 words

I got to play with Monad today, so here are a few quick impressions:

  • No environment variables, I tried to do a cd %windir% and it didn't expand it.
  • Auto completion for file names gives the full path, unlike cmd, which gives relative path, this is very annoying, actually.
  • You get auto completion for cmdlets (Cool), but not for .Net's namespaces (Not Cool).
  • Trying to run a script normally doesn't work: regex.msh fails, while .\regex.msh succeeds, I've no idea why, they are functionaly identical.
  • It's fun to work with.

Here is a small script that handles extracting regex expression from files:

if($args.Count -lt 2)
{
 "Arguments are: <file> <regex-pattern>"
 break
}
$file = [string]$args[0]
$pattern = [string]$args[1]
$re = new-object System.Text.RegularExpressions.Regex($pattern)
foreach ($line in $(Get-Content $file))

 $match = $re.Match($line); 
 if($match.Success) 
 {
  $match.Value
 }
}

Here is how you would get all the ifs in a script:

MSH C:\Documents and Settings\Ayende\My Documents>.\regex.msh regex.msh "(?<=if\().+(?=\))"
$args.Count -lt 2
$match.Success

Worst Job Ever

time to read 1 min | 169 words

Inspired by My Worst Job & What are some crappy jobs you've worked?

My worst job was at a butcher. I was 14, I think. I worked for less than minimum wages (I think it translate to about 1.05$ an hour in today's rates) and the hours were terrible. My job consisted of taking a chicken and reduce it to edible parts. It was a good place to learn about anatomy, but the owner kept asking why I'm washing my hands so often. It's not recommended to those with queasy stomaches.

Along the way I learned that a chicken cost 30 NIS (6.5$), and a chicken I cut to parts cost around 90 - 110 NIS (20$). I quit after about a week, and it took me a while to even go near the shop. I'm proud that even after that, I'm not a vegeterain. :-)

[Listening to: תשאירי לי פרח - שוטי הנבואה - title(04:46)]

The REPL in .NET

time to read 2 min | 279 words

A post in Project Aardvark biog by Benjamin Pollack contains some very disturbing ideas:

Thirdly, you can’t easily write and test just a small amount of code. In most languages, your only option if you want to do this is to write a test suite for your class protocol, which takes a lot of time during development and probably isn’t necessary for a lot of smaller stuff.

Didn't you guys heard about Test Driven Development? You can get it in most languages now aday. In .Net, the common framework is NUnit (but I like MbUnit as well). In C++, you have CppUnitLite. The issues he is describing sounds like normal legacy code and can be solved using the techniques listed in Working Effectively With Legacy Code.

REPL is nice, but it is good for playing with the langauge; to see what will happen if you do XYZ, not to verify that XYZ indeed happens. I know that Joel's Test doesn't include Unit Testing, but still...

This is sad. Benjamin, get yourself a copy of the following books and read them, you'll likely learn a lot.

Product image for ASIN: 0735619484 Test-Driven Development in Microsoft .NET

Product image for ASIN: 0596007396 NUnit Pocket Reference

time to read 3 min | 509 words

I made quite a progress, mostly thanks to this article. I'm totally and completely blown away by the capabilities of Castle.DynamicProxy, it open up a whole world of facinating possibilities.

For instance, I wanted to get rid of this type of code:

MockControl mockView = new MockControl.CreateControl(typeof(IView));
IView view = mockView.MockInstance as IView;
view.DoSomething();
mockView.ReturnsFor(3, someVal);

I wanted to be able to do something much simpler, like this:

MockRepository mocks = new MockRepository();
IView view = mocks.CreateMock(typeof(IView));
view.DoSomething();
LastCall.On(view).Returns(someVal).Repeat(3);

It doesn't look like a great improvement, doesn't it? But this means that you no longer has to sync two objects for each mock. I thought a lot about how I would implement this in my code. LastCall is a static class, and has no information about the mocked instance beyond what I'm passing as an argument. I needed some way to get to the MockRepository from the mocked instance.

I though about using a static table, with all the mocked instances as keys, and the value being the MockRepository. But this has several disadvantages, chief among them are:

  • It's ugly hack.
  • It's a huge memory leak, those objects would never be released as long as the AppDomain is loaded.

What I really wanted was to do this:

public static IMethodOptions On(object mockedInstance)
{
   IMockedObject mockedObj = mockedInstance as IMockedObject;
   //error handling if mockedObj is null
   return mockedObj.Repository.MethodOptions[mockedInstance];
}

Using Castle.DynamicProxy, it was as easy as modifying the types implemented by the mocked object, and handling the type with the interceptor. It took me some time to figure it out, but when I did, it was so easy that I couldn't believe. So the above code is not possible due to around three or four lines of code. And I'm very pleased to find a new tool.

time to read 3 min | 561 words

I finally got the excuse to work on Rhino Mocks again :-)

I've a line in one of my presenters that looks like this:

IView[] toSave, unsaved = (IView[]) unSavedList.ToArray(typeof (IView));

Unfortantely, when I pass mocked IViews to this method, the following exception is raised: "System.InvalidCastException : At least one element in the source array could not be cast down to the destination array type."

The issue seems to be that Rhino Mocks is uing remoting proxies to do its work, and that doesn't sit well with Array.Copy(). So now I got two choices, I can modify the production code* so it would work with remoting proxies (basically avoiding the ArrayList.ToArray() and the Array.Copy() methods). Or, I can rip the guts out of Rhino Mocks and replace it with something that I like better. The two options I see now are:

  • either, use Castle.DynamicProxy.
  • or, write my own proxies using Reflection.Emit.

Pros for Castle.DynamicProxy:

  • It's nearly literally two lines of code.
    ProxyGenerator generator = new ProxyGenerator(); 
    return generator.CreateProxy(destinationType,new RhinoInterceptor(),source);
  • I'll be using tried and tested library with quite a bit of support.
  • I can get it out nearly instantly.

Cons for using Castle.DynamicProxy:

  • It means another library to carry with Rhino.Mock.

Pros for rolling my own:

  • It will teach me quite a bit about Reflection.Emit and IL

Cons for rolling my own:

  • I'm not likely to get it right on the first (or even second) attempt.
  • After looking at NMock's source, it looks like routine stuff, the moment you get it.
  • It'll take quite a bit of time.

Looking at it this way, I think that it's no brainer what I'll use :-)

* This is acceptable under normal circumstances, but a bug** in the mocking library doesn't fall under the defination of nomral circumstances.

** Yes, it's a bug, a mock should be just like the object it replace.

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. Production postmorterm (2):
    11 Jun 2025 - The rookie server's untimely promotion
  2. Webinar (7):
    05 Jun 2025 - Think inside the database
  3. Recording (16):
    29 May 2025 - RavenDB's Upcoming Optimizations Deep Dive
  4. RavenDB News (2):
    02 May 2025 - May 2025
  5. Production Postmortem (52):
    07 Apr 2025 - The race condition in the interlock
View all series

Syndication

Main feed ... ...
Comments feed   ... ...
}