> Mike Valenty

Integration Testing With NHibernate

| Comments

While the first-level cache in NHibernate is great for production, it can be super annoying for integration tests. Basically I just want to make sure my mapping works and that when I save an entity it goes to the database.

1
2
3
4
5
6
7
8
9
10
11
12
13
[TestFixture]
public class MyIntegrationFixture : IntegrationFixture {
    [Test]
    public void Can_add_elements() {
        var repository = Container.Resolve<IRepository<MyEntity>>();

        var entity = repository.FindById(1);
        entity.Add(new Element { Description = "The Description" });
        repository.Save(entity);

        Assert.That(repository.FindById(1).Elements.Count(), Is.EqualTo(1));
    }
}

The problem is the next time I call FindById() I get my object back from the first level cache ISession, so the Assert passes but looking at the SQL output by NHibernate I can see that no INSERT statement is happening. There are two things that NHibernate needs to do in order for the integration test to work as expected.

  1. There needs to be an explicit transaction and it needs to be committed in order to actually send the INSERT statements to the database.
  2. The entity needs to be evicted from the session in order to ensure that the next call to FindById() actually goes to the database.

It’s the job of the application to manage the scope of the unit of work. Typically this is per web request in a web app. In a test, it’s per test. This turns into a bunch of boiler-plate noise. Also, this business about evicting the session is an NHibernate specific thing and doesn’t belong in a test that is dealing with an IRepository abstraction.

Since I solve all my problems with a pipeline or decorator, I figured I’d decorate the ISession and commit and evict on the operations I care about:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class AutoCommitAndEvictSession : SessionDecorator {
    public AutoCommitAndEvictSession(ISession session)
        : base(session) {
    }

    public override object Save(object obj) {
        object result;
        using (var tx = Session.BeginTransaction()) {
            result = Session.Save(obj);
            tx.Commit();
        }
        Session.Evict(obj);
        return result;
    }

    public override void Update(object obj) {
        CommitAndEvict(base.Update, obj);
    }

    public override void SaveOrUpdate(object obj) {
        CommitAndEvict(base.SaveOrUpdate, obj);
    }

    public override void Delete(object obj) {
        CommitAndEvict(base.Delete, obj);
    }

    private void CommitAndEvict(Action<object> action, object entity) {
        using (var tx = Session.BeginTransaction()) {
            action.Invoke(entity);
            tx.Commit();
        }
        Session.Evict(entity);
    }
}

Then I just work it into a test fixture like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[TestFixture]
public abstract class IntegrationFixture {
    protected IUnityContainer Container { get; private set; }
 
    [TestFixtureSetUp]
    public virtual void TestFixtureSetUp() {
        Container = new UnityContainer()
            .AddNewExtension<ConfigureNHibernate>();
    }
 
    [TestFixtureTearDown]
    public virtual void TestFixtureTearDown() {
        Container.Dispose();
    }
 
    [SetUp]
    public virtual void SetUp() {
        var session = Container.Resolve<ISessionFactory>().OpenSession();
        Container.RegisterInstance<ISession>(new AutoCommitAndEvictSession(session));
    }
 
    [TearDown]
    public virtual void TearDown() {
        Container.Resolve<ISession>().Dispose();
    }
}

Moq Extension Methods for Unity

| Comments

A few people have asked about the RegisterMock extension method used in another post. The usage looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Test]
public void Should_delete_removed_image()
{
    container.RegisterMock<IFileRepository>()
        .Setup(r => r.Delete(It.IsAny<IFile>()))
        .Verifiable();

    container.RegisterMock<IBusinessRepository>()
        .Setup(r => r.FindById(3))
        .Returns(CreateBusinessWith(new BusinessImage { ImageId = 4 }));

    var controller = container.Resolve<BusinessGalleryController>();
    controller.Delete(3, 4);

    container.VerifyMockFor<IFileRepository>();
}

It’s just a few helper extensions for using Moq with Unity that cut down on the noise in tests. My friend Keith came up with it, I just happen to blog about it first. Here it is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public static class MoqExtensions
{
    public static Mock<T> RegisterMock<T>(this IUnityContainer container) where T : class
    {
        var mock = new Mock<T>();

        container.RegisterInstance<Mock<T>>(mock);
        container.RegisterInstance<T>(mock.Object);

        return mock;
    }

    /// <summary>
    /// Use this to add additional setups for a mock that is already registered
    /// </summary>
    public static Mock<T> ConfigureMockFor<T>(this IUnityContainer container) where T : class
    {
        return container.Resolve<Mock<T>>();
    }

    public static void VerifyMockFor<T>(this IUnityContainer container) where T : class
    {
        container.Resolve<Mock<T>>().VerifyAll();
    }
}

Domain Driven Design in the Small

| Comments

A few months ago we built a Magento extension to send orders to a product supplier via soap for payment and fulfillment along with affiliate tracking. As part of the process, a contact record was created in the affiliate’s CRM account.

Recently, the stake holders came up with a twist that went something like this: If the order contains a gift card, add the contact to a specific folder in the CRM application. No big deal, we had a nicely abstracted OrderGateway interface and I was already envisioning a quick addition to the existing decorator chain.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class OrderWithGiftCardGateway extends OrderGatewayDecorator
{
    ...

    public function createOrder(CreateOrderRequest $order)
    {
        if ($this->containsGiftCard($order))
        {
            $this->addContactToFolder($order);
        }

        return parent::createOrder($order);
    }
}

I had a few minutiae questions like what happens with duplicates, etc. It took me nearly an hour to track down the right person and get real answers. During the conversation, a subtle comment was made that I almost missed.

Stake holder: We should check with the product supplier to make sure the gift card sku I made up isn’t for a real product.

Me: Say what?

Stake holder: The gift card is not fulfilled by the product supplier, it’s fulfilled by the affiliate.

Me: %$@!&, I’m glad we had this conversation.

We talked about what it meant for the the affiliate to fulfill the product and basically the folder stuff was okay, but I recommended we remove the fake sku from the order before sending it through.

1
2
3
4
5
6
7
8
9
10
public function createOrder(CreateOrderRequest $order)
{
    if ($this->containsGiftCard($order))
    {
        $this->addContactToFolder($order);
        $this->removeGiftCardFromOrder($order);
    }

    return parent::createOrder($order);
}

I didn’t have a buddy to pair with so I just grabbed Keith for a minute at the end of the day to walk through things. I recapped the stake holder discussion and we looked through the code. He pointed out I was missing the concept of fulfillment and that was hard earned knowledge that would be lost!

1
2
3
4
5
6
7
8
9
10
public function createOrder(CreateOrderRequest $order)
{
    if ($this->containsGiftCard($order))
    {
        $this->sendToAffiliateForFulfillment($order);
        $this->removeGiftCardFromOrder($order);
    }

    return parent::createOrder($order);
}

That was huge. – Paris Hilton

Why was that huge? Because it changed the conversation. Right away we thought of important requirements like this should be in a transaction with the order and the template email the affiliate gets should include the customer’s address, etc.

It tells an important story for the next guy looking at the code and it changes the role of the programmer from code monkey to business partner. Maybe you think I’m crazy, but this stuff matters to me.

The Holy Trinity of Web 2.0 Application Monitoring

| Comments

We had just rolled out a new system for a client and they were doing a high profile launch of their product. We had all our normal monitoring in place like CPU, memory, connections and page load time. Everything was swell…

On their signup form, we did an ajax call to check if their desired username was available. If it wasn’t, we displayed a validation error an prevented the user from submitting the form. Turns out our little jquery script was silently bombing out and always returning ‘false’ meaning nobody could sign up!

This little issue slipped through the cracks and it hurt pretty bad. I couldn’t just tell the stake holders “sorry”, I needed something a little better so I spent some time with Matt, our super do-everything networking guy, and we put together the holy trinity of web 2.0 application monitoring (insert enlightenment music here).

We were already using Nagios for monitoring and alerting, CruiseControl for running unit tests, and Selenium for automated web application testing. We just needed to glue it all together!

  1. The first step was to write a selenium test to go through the online order sequence. We then exported it as a phpUnit test and dropped it in a our svn repository in a folder named “monitoring.”
  2. Next, we configured a CruiseControl project named “selenium-bot” to pull down all the phpUnit tests from the “monitoring” folder in svn and run the whole test suite every 10 minutes.
  3. The last step was to use Nagios to monitor the CruiseControl log file to make sure it was actually running every 10 minutes and returning all green. If anything stops working, Nagios takes care of the alerting.

I should also mention that since this hits the live online order form every 10 minutes, we needed a way to a way to short circuit the test orders. Fortunately, we already had a convenient OrderGateway interface, so we were able accomplish this in a very open-closed manner using the decorator pattern:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class TestOrderInterceptor implements OrderGateway
{
  const TEST_CODE = '843feaa7-bf13-4aff-91f6-a074434f9c14';
  const SUCCESS_RESULT = 1;

  private $orderGateway;
  private $logger;

  public function __construct(OrderGateway $orderGateway, Logger $logger)
  {
    $this->orderGateway = $orderGateway;
    $this->logger = $logger;
  }

  public function createOrder(CreateOrderRequest $order)
  {
    if ($this->isTest($order))
    {
      $this->logger->debug('test order intercepted');
      return self::SUCCESS_RESULT;
    }

    return $this->orderGateway->createOrder($order);
  }

  private function isTest($request)
  {
    return strpos($request->name1, self::TEST_CODE) !== false;
  }
}

The decorator chain is wired up using PicoContainer, and looks like this:

1
2
3
4
5
$pico->regComponentImpl('SoapOrderGateway', 'SoapOrderGateway');

$pico->regComponentImpl('OrderGateway', 'TestOrderInterceptor', array(
    new BasicComponentParameter('SoapOrderGateway'),
    new BasicComponentParameter('Logger')));

This infrastructure has paid dividends more than a few times and now I can’t imagine rolling out a site without it.

Default Interceptor for Unity

| Comments

Default: the two sweetest words in the English language – Homer Simpson

Unity interception requires you to specify what kind of interceptor to use for each type you want to intercept. This can be a little painful, so I decided to take a stab at a container extension that will apply a default interceptor with optional matching rules.

This is how I want it to look:

1
2
3
4
5
container
    .AddNewExtension<InterceptOnRegister>()
    .Configure<InterceptOnRegister>()
    .SetDefaultInterceptor<TransparentProxyInterceptor>()
    .AddMatchingRule(new AssemblyNameStartsWith("MyCompany"));

The basic idea here is to subscribe to the register events and configure interception if it meets our criteria. By default it will match everything and apply TransparentProxyInterceptor, but as you can see from the snippet above, you can explicitly supply another interceptor and matching rules.

Here it is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
public class InterceptOnRegister : UnityContainerExtension {
    private IInstanceInterceptor interceptor;
    private readonly IList<IInterceptRule> rules;

    public InterceptOnRegister() {
        interceptor = new TransparentProxyInterceptor();
        rules = new List<IInterceptRule> {
            new NotUnityInterceptionAssembly(),
            new DoesNotHaveGenericMethods() };
    }

    public InterceptOnRegister AddMatchingRule(IInterceptRule rule) {
        rules.Add(rule);
        return this;
    }

    public InterceptOnRegister AddNewMatchingRule<T>() where T : IInterceptRule, new() {
        rules.Add(new T());
        return this;
    }

    public InterceptOnRegister SetDefaultInterceptor<T>() where T : IInstanceInterceptor, new() {
        interceptor = new T();
        return this;
    }

    protected override void Initialize() {
        AddInterceptionExtensionIfNotExists();

        Context.Registering +=
            (sender, e) => SetInterceptorFor(e.TypeFrom, e.TypeTo ?? e.TypeFrom);
    }

    private void AddInterceptionExtensionIfNotExists() {
        if (Container.Configure<Interception>() == null) {
            Container.AddNewExtension<Interception>();
        }
    }

    private void SetInterceptorFor(Type typeToIntercept, Type typeOfInstance) {
        if (!AllMatchingRulesApply(typeToIntercept, typeOfInstance)) {
            return;
        }

        if (interceptor.CanIntercept(typeOfInstance)) {
            Container
                .Configure<Interception>()
                .SetDefaultInterceptorFor(typeOfInstance, interceptor);
        } else if (interceptor.CanIntercept(typeToIntercept)) {
            Container
                .Configure<Interception>()
                .SetDefaultInterceptorFor(typeToIntercept, interceptor);
        }
    }

    private bool AllMatchingRulesApply(Type typeToIntercept, Type typeOfInstance) {
        foreach (var rule in rules) {
            if (!rule.Matches(typeToIntercept, typeOfInstance)) {
                return false;
            }
        }

        return true;
    }
}

And you’ll need this stuff too:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public interface IInterceptRule {
    bool Matches(Type typeToIntercept, Type typeOfInstance);
}

public class NotUnityInterceptionAssembly : IInterceptRule {
    public bool Matches(Type typeToIntercept, Type typeOfInstance) {
        return !typeToIntercept.Assembly.Equals(typeof(Interception).Assembly);
    }
}

public class DoesNotHaveGenericMethods : IInterceptRule {
    public bool Matches(Type typeToIntercept, Type typeOfInstance) {
        return typeOfInstance.GetMethods().Count(m => m.IsGenericMethod) == 0;
    }
}

public class AssemblyNameStartsWith : IInterceptRule {
    private string match;

    public AssemblyNameStartsWith(string match) {
        this.match = match;
    }

    public bool Matches(Type typeToIntercept, Type typeOfInstance) {
        return typeOfInstance.Assembly.FullName.StartsWith(match);
    }
}