NH Prof Deep DiveThe Integration Test Architecture
I am getting a lot of requests to explore the actual innards of the NH Prof. I find it surprising, because I didn't think that people would actually be interested in that aspect of the tool.
But since interest was expressed, I'll do my best to satisfy the curiosity.The first topic to discuss is the integration test architecture. One of the things that the profiler is doing is to capture data from a remote process, and I wanted my integration tests to be able to test that scenario, which exposes me to things like synchronization issues, cross process communication and (not incidentally), allows me to test scenarios that looks just like real code.
The integration tests project for NH Prof is not a dll, it is an executable. And when you execute it you can ask it to run a specific scenario (specified using command line parameters).
Let us take an example of such scenario:
public class SelectBlogByIdUsingCriteria : IScenario
{
public void Execute(ISessionFactory factory)
{
using (var session = factory.OpenSession())
using (var tx = session.BeginTransaction())
{
session.CreateCriteria(typeof(Blog))
.Add(Restrictions.IdEq(1))
.List();
tx.Commit();
}
}
}
And now that I have the scenario, we can write a test that uses it. Here is the first test that I wrote using this approach:
[TestFixture]
public class CanGetDataFromSeparateProcess : IntegrationTestBase
{
[Test]
public void SelectBlogById()
{
ExecuteScenarioInDifferentProcessWithDefaultConfig<SelectBlogByIdUsingCriteria>();
var sessionModel = observer.Model.Sessions.First();
StatementModel selectBlogById = (StatementModel)
sessionModel.Statements.Where(x=>x is StatementModel).First();
const string expected = @"SELECT this_.Id as Id\d_\d_,
this_.Title as Title\d_\d_,
this_.Subtitle as Subtitle\d_\d_,
this_.AllowsComments as AllowsCo\d_\d_\d_,
this_.CreatedAt as CreatedAt\d_\d_
FROM Blogs this_
WHERE this_.Id = 1";
Assert.IsTrue(Regex.IsMatch(selectBlogById.Text, expected),selectBlogById.Text);
}
}
There are a couple of interesting things going on here. First, we can see the IntegrationTestBase, which has methods such as ExecuteScenarioInDifferentProcessWithDefaultConfig (the config controls the communication mechanism).
Then, all I need to do is assert on the actual model that was built as a result of executing the scenario.
Executing the scenario involves running the integration test project as an executable, and passing it the scenario to execute. This tests cross process communication, expose threading issues and in general means that I have a realistic view of what is going to happen in the actual application.
More posts in "NH Prof Deep Dive" series:
- (24 Dec 2008) Implemented the Unbounded Result Set warning
- (24 Dec 2008) Applying the Open Close Principle at the architecture level
- (06 Nov 2008) The Integration Test Architecture
Comments
Just a quick off-topic regarding enumerable extension methods:
you can replace this:
StatementModel selectBlogById = (StatementModel)
with this:
StatementModel selectBlogById =
<statementmodel().First();
Which avoids the explicit cast and is more intention-revealing.
Er... did subtext just eat my generic parameters because they looked like Xml?
I meant Statements.OfType<StatementModel>().First(), of course.
Comment preview