Los Techies was kind enough to let me join their inner circle. Hopefully the hazing won't be too bad.
You can follow
my blog here now
So long, and thanks for all the fish.
While trying to get up to speed on using Castle’s ActiveRecord framework, one of the first things I needed to do was figure out how to test my ActiveRecord objects. There are some a good articles that describes how to us a base test class to get your unit tests up and running.
In a nutshell you need to have a TestFixtureStartup to initialize ActiveRecord. You need to call the ActiveRecordStarter.Initialize to get AR ready to go.
However, I have yet to find to opposite of this method to stop ActiveRecord on TestFixtureTearDown. This becomes a problem when you have multiple test classes. AR will yell at for already creating an instance. I solved this with a static guard variable.
private static bool _isActivated = false;
…
if(!_isActivated)
{
_isActivated = true;
ActiveRecordStarter.Initialize(source, typeof(…));
}
If there is a better way of doing this please let me know.
One very cool thing is that you can leverage Nhibernate’s ability to create and drop schemas. ActiveRecordStarter.CreateSchema() will create your database schema based off of your ActiveRecord classes. I like this feature, though I wouldn’t use it for real integration tests because I want to make sure that my database migration process works when I deploy to production.
Castle’s ActiveRecord frame work is an easy way to get introduced to NHibernate if you’re not familiar with setting up and using NHibernate (which I’m not). However many people are not fond of the ActiveRecord pattern. It can be a leaky abstraction, putting persistence related functions on your domain model is not a very clean separation of concerns for many people. I tend to agree with this. It really does depend on the complexity of your application.
When learning about AR I read a lot of blog entries or the documentation, people elude to how you can use AR API in a repository fashion, but I could find very few examples of how to uses.
It turns out there is an innocuous object within the API call ActiveRecordMediator<T>. This little guy has all of the persitance related methods you normally call directly on your ActiveRecord object. With this object you can use a Repository style DAL. Here is my simple BaseRepository that I inherit from to take advantage of ActiveRecordMediator. You can extend this further of course, but it’s all I need at the moment.
public class BaseRepository<T> : IRepository<T> where T :class
{
protected ActiveRecordMediator<T> mediator;
public virtual void Save(T item)
{
ActiveRecordMediator<T>.Save(item);
}
public virtual T FindById(object id)
{
return ActiveRecordMediator<T>.FindByPrimaryKey(id);
}
public virtual T FindOne(params ICriterion[] criteria)
{
return ActiveRecordMediator<T>.FindOne(criteria);
}
public virtual T[] FindAll()
{
return ActiveRecordMediator<T>.FindAll();
}
public virtual int Count()
{
return ActiveRecordMediator<T>.Count();
}
}
This example shows two of my favorite things about jQuery: chainable methods and the find method. The find method is the easiest way to find decendent objects. There are many other ways, but when you to perform work on the parent and the child, chaining the work keeps the code tight and reduces the number of object that must be created
Let's say you have something like this:
<div id='containerForList'>
<span id='listLabel>Description of List Goes Here</span>
<ul><!-- items go here -->
</ul>
</div>
And you need to perform several tasks. Display the Container and Add a new Item to the UL.
There are several ways to get to it. You can separate this into two calls, create an object for the div and then create an object for the ul and perform the tasks on those seperately. Another approach is to chain these actions together.
$('#containerForList').show().find("ul").append("<li>A new Item to the list</li>");
Of course like all examples, they are always too contrived, but you get the idea.
So you may have heard the Alt.Net moniker being thrown around. You might have become curious enough to read David Laribee. But do you want to learn where the rubber meets the metal?
Join the AltNetConf User Group and subscribe to the mailing list. This is becoming a very active group where people are asking questions about how people are using different strategies facing just about every .net (or otherwise) out there when it comes to building and testing coherent and maintainable software. Contrary to what other people in the blogosphere are saying, this is a very open group and appreciate open dialog. There are some threads on there that are about the growing pains that any new community goes through. You can skip those if you want. I usually read one or two so I know what the discussion about.
There have been plenty of posts about the new asp.net MVC framework that was posted from the alt.net conference. There's very little that I can add to those posts other than I am really excited.
Right after that Scott Hanselman (the link to the video is in this link) did a demo of possible ways the MVC could be used to along with the Dynamic Language Runtime. Not only is the MVC code in prototype, but Scott really only had a couple days to show how you could use the DLR with it, so obviously what was shown was rough around the edges. Which is fine, because what the sessions was for (and the conference for that matter) was to spark you imagination.
What he showed was that it's possible to do the View or the Controller in a dynamic runtime and leave your Model in the CLR. To me that's huge, because now I can take the parts I like about Ruby on Rails (view helpers first and formost) and use C# to do my entity objects. To me this goes hand in hand with the principels of agile, use the best tools for the job and don't repeat yourself.
It will be great to just pick the best language and not worry about dynamic vs static.
So I've got this pet project of mine that I'm trying to work on in my spare time (hehehe). I started this for several reasons, mainly I need an application that I can sink my teeth into.
I've gone down several paths on how to implement it, from a Javascript view to MonoRail to a smart client. I've finally settled down to using Ruby on Rails to do it. This is the most ambitious choice given my utter lack of knowlege in Ruby and Rails.
So most of my posts will be focused on what I'm learning in the process. The first thing is the Migrations Rock!! We have our own migration-ish nant task to some of what migrations give you. Now I want to use migrations completely and wire it into our nant task. Moving completely to Rake would be cool, but we have way too many assets in nant for us to make that switch.
So the Alt.Net Conference is over, and let me tell you it was an amazing experience.
I've been reading some of the early reactions on the blogs and had some conversations over a great lunch after the conference. Two of them that were not issues for me was the "Echo Chamber" and "Preaching to the Choir". These are legitmate and if you've been doing this for a couple years and have the expertice like
Jeremy,
Jeffrey or Scott Hanselman I can understand.
But for these were not issues. While I've been reading about these concepts for years and have been trying to use them in environments where it was not the norm or even appreciated, it was like physists going to a Nobel Prize luncheon. I got to pick people's brain about the best practices, why is done this way and not another way, and hopefully avoid some pitfalls.
The other thing that was great for me was the confirmation that I am not alone in the way I want to build software and the way I think it should be done. For all of you who have been trying agile practices in an non-agile environment, I know you understand.
When running this test
Sprint s = new Sprint();
ValidationResult<Sprint> result = new ValidationResult<Sprint>();
result.Result = true; using(mocks.Unordered())
{
Expect.On(sprintRepository).Call(sprintRepository.Save(s)).Return(result);
Expect.On(view).Call(view.ErrorMessage).PropertyBehavior().Return(string.Empty);
}
mocks.ReplayAll();
presenter.SaveSprint();
mocks.VerifyAll();
I ran across this exception
Rhino.Mocks.Exceptions.ExpectationViolationException: ISprintRepository.Save(SprintVelocity.Domain.Sprint); Expected #0, Actual #1.
ISprintRepository.Save(SprintVelocity.Domain.Sprint); Expected #1, Actual #0.
I took some time to research this problem and I found some other interesting things in the process. First of all the reason of this error is because of the Sprint object is different in the SaveSprint() method than the Sprint object in the test. This was fixed by using the IgnoreArguments() method. It's a rookie mistake, but hey someone got to own up to it so you can find the solution right.
It's hard to tell that from the error messages, which leads into one of my discoveries while fixing this:
Override the ToString method to get better messages.
If I override ToString in the Sprint Class, the previous exception becomes this:
Rhino.Mocks.Exceptions.ExpectationViolationException: ISprintRepository.Update(Sprint: ID=0;ProjectId=1; Description=description; Start-Date:2007-09-04 00:09; End-Date=2007-09-04 14:09
); Expected #0, Actual #1.
ISprintRepository.Update(Sprint: ID=0;ProjectId=null; Description=; Start-Date:0001-01-01 00:00; End-Date=0001-01-01 00:00
); Expected #1, Actual #0.
Now I know what is happening and how to fix it.
The other new discovery is that you can put Rhino Logging messages into the output. Add the following lines to you SetUp method and you will get Rhino Mocks logging messages in the console.
.Logger = new TextWriterExpectationLogger(Console.Out);
Resharper's TestRunner puts this in the same output as the results, so it's easy to see where Rhino blew up.
Recorded expectation: ISprintRepository.Update(Sprint: ID=0;ProjectId=null; Description=; Start-Date:0001-01-01 00:00; End-Date=0001-01-01 00:00
);
Recorded expectation: ISprintFormView.get_ErrorMessage();
Unexpected method call error: ISprintRepository.Update(Sprint: ID=0;ProjectId=1; Description=description; Start-Date:2007-09-04 00:09; End-Date=2007-09-04 14:09
);
Anyway, those are my Rhino Mock epiphanies for the week. I hope they help someone else.
Cheers,