Source Allies Logo

Sharing Our Passion for Technology

& Continuous Learning

<   Back to Blog

Beanoh.NET: Spend Less Time Verifying Spring.NET contexts

I Love Dependency Injection But ....

I've burned myself so many times with dependency injection in the past. It make me nervous when I see a complex software product comprised of multiple projects and dozens of libraries without any comprehensive test that double checks the wiring. As our wiring grows and changes over time we need to continuously verify that everything works together. Dependency injection is one of the most valuable patterns in software development. Spring.NET is a necessity in today's world and has great power that we need to harness in our products. With software products getting bigger and bigger, Spring.NET turns into a double edged sword that can hurt us especially if we cannot prove that every object is wired properly.

Beanoh.NET is a powerful tool for designing and maintaining Spring.NET configurations. One time I had an object named "messageSender" and that object controlled an HTTP connection to a web service by specifying a timeout for connecting and reading the HTTP stream. One day I needed to up the read timeout but for the life of me I couldn't figure why the call was timing out after 15 seconds even though I've increased the timeout to 30 seconds. I spent hours looking into the documentation of the HTTP sender and debugged the code to no avail. In a moment of despair, I ran an Agent Ransack search through the whole web application package for the word "messageSender" and found two objects with that name one with 15 seconds timeout and the other with 30 seconds timeout. Each pulled from a different library. Wouldn't it be awesome if my continuous build failed with a message saying "a duplicate object definition was found with the name of 'messgeSender'. Are you sure you want them overriding each other?" If I was using Beanoh.NET it could have identified this duplicate bean.

Another example, my project was pulling an object from a library and the object was named "badlyNamedObject". Then one day when I changed that object name to something more meaningful like "properlyNamedObject", my project started throwing errors. Unfortunately this error went unnoticed for two weeks because this object was not used frequently. Two weeks is a long time. A lot of dependencies can change in two weeks. Several painful debugging hours later, I found the name change and fixed my problem. Wouldn't it be awesome if my continuous integration build failed shortly after I started using the new library and said "cannot find 'badlyNamedObject' when loading the context"? It would have taken me less than 1 minute to fix it. Beanoh.NET reports any configuration errors that exist in your Spring.NET configuration.

These examples and many more are the reason why our teams always add Beanoh.NET tests for every new library we create. We learned to rely on Beanoh.NET the hard way, but you don't have to. Start using Beanoh.NET today.

.... Enter Beanoh.NET

Beanoh.NET, pronounced 'beanˌō dot net, is a simple open source tool for verifying your Spring.NET context. Teams that leverage Beanoh spend less time focusing on configuring Spring.NET and more time adding business value.  Beanoh.NET is the .NET cousin of the Java version called Beanoh.

You can install Beanoh.NET to your project using Nuget Package manager plugin for Visual Studio (this is the preferred way so that all dependencies are resolved) by searching for Beanoh. For more instructions refer to Nuget documentation and the beanoh package.

For licensing information refer to the license section.

Features

  1. Verifies that all of your objects defined in Spring.NET are wired correctly
  2. Detects duplicate object definition, i.e. override detection

Why do I need Beanoh.NET ? Aren't unit tests enough?

That's probably the first question that comes to mind when talking about Spring.NET context tests. As we all know, there are several types of unit tests in terms of Spring contexts:

  1. Unit tests in complete isolation. These type of tests verify a single class or service by stubbing/mocking its dependencies using frameworks like Moq, Nmock, etc. These tests make your dependencies static so you can control their behavior. In these type of tests, you're not testing the Spring context at all
  2. Unit tests that verify the functionality of an object fetched from the context. This type of test will test the Spring context partially because you are only testing the dependency wiring of the object you retrieved from the context. If you're using IObjectFactory implementation, for the sake of performance and efficiency, it won't construct every singleton object defined in the context when you load the context. This is understandable because if you have a large context, it will take a long time which you might not want to wait for during a unit test that only needs 5 objects wired. Of course, if you use the IApplicationContext, it will create every singleton object by default unless you specified lazy-init="true". But what about request and session scoped objects? Spring creates the objects when you ask for them. If your test does not need object A , it will not create it until you ask for it. Hence, you are not guaranteed that the entire Spring.NET context is loaded.
  3. Beanoh.NET Tests. These type of tests will assert your context by requesting each bean in a Spring context. This guarantees that Spring actually constructs each object and wires its dependencies. Another advantage of Beanoh is that it will detect duplicate object definitions. When Spring sees that you're defining a second object with the same ID as a previously loaded object, it will replace the old object with the new one. If you have logging defined properly, you might see this overriding action in the logs, but it's not considered an error because you might have a valid case where you want to override some beans. With Beanoh, you have the ability to detect those duplicate definitions. You have the choice of making the test fail if such definitions are found or you can instruct Beanoh to ignore specific duplicated beans.

Writing Beanoh.NET Test Fixtures

Beanoh.NET follows simple conventions so that you will spend less time learning Beanoh.NET and more time coding. Your NUnit test fixture needs to extend the base SourceAllies.Beanoh.BeanohTestCase test fixture, and you need one Spring.NET bootstrap context that loads all the contexts you want to verify. The bootstrap context needs to be in a specific location and named in a specific way for it to be picked up by Beanoh.NET. We will talk about those requirements shortly.

a. Assert Context Loading

For example, let's say we want to verify a Spring.NET context found in assembly://MyAssembly/My.Cute.Namespace/someSpringContext.xml that defines objects and wires them together. First we create a NUnit Test Fixture, let's call it BasicWiringTest. This test needs to extend SourceAllies.Beanoh.BeanohTestCase test fixture.

//Our Code will look like this
namespace My.Tests.Verbose.Namespace
{
    [TestFixture]
   public class BasicWiringTest : BeanohTestCase
    {
        [Test]
        public void TestWiring()
        {
            AssertContextLoading();
        }
    }
}

To verify every object definition in our Spring.NET context we need to define a test method TestWiring() that calls the BeanohTestCase.AssertContextLoading() method.

Next, we need to define a bootstrap context that we mentioned earlier. For now all you need to know is the following criteria :

  1. The context must to be named X-BeanohContext.xml. Where X is the name of your Test Fixture class. For our example the context name is BasicWiringTest-BeanohContext.xml.
  2. It needs to be in the same assembly as the test fixture.
  3. It has to be in the same namespace as the test fixture. For that to happen, we just put the xml file in the same folder as our test fixture so that it will have the same namespace as the test fixture. In our example the context will be resolved using assembly://MyAssembly/My.Tests.Verbose.Namespace/BasicWiringTest-BeanohContext.xml assuming that the test fixture is part of MyAssembly.
  4. It needs to be defined as an embedded resource so it will be copied along with our test fixture during compilation, packaging and execution.
<!-- BasicWiringTest-BeanohContext.xml bootstrap context will be as follows -->
<objects xmlns="http://www.springframework.net">
  <import resource="assembly://MyAssembly/My.Cute.Namespace/someSpringContext.xml"/>
</objects>

Now, you can just run the test and let Beanoh.NET do its magic.

Note: Something to point out is that when the bootstrap conforms to these criteria you will find the test fixture class and the context together in the same namespace in the generated DLL. If you have issues running the test and you get a message saying it couldn't find the context, inspect the tests assembly DLL and verify that the bootstrap context and test fixture have the same namespace. You can inspect the DLL using a tool like CodeReflect.

Note: In future Beanoh.NET releases, we plan on adding some flexibility around how to define the bootstrap context.

b. Assert No Duplicate Object Definitions

Another feature of Beanoh.NET is that it can identify if you have duplicate object definitions. We have all run into situations where we are trying to troubleshoot an issue and after a painful debugging session we find out that we pulled in some context that defined another object with the same id and that's the one being used by our program.

Beanoh.NET can detect this issue. Simply call the method BeanohTestCase.AssertUniqueObjectContextLoading() instead of BeanohTestCase.AssertContextLoading().

//our code will look like this
namespace SourceAllies.Beanoh.Duplicate
{
    [TestFixture]
    class DuplicateObjectTest : BeanohTestCase
    {
        [Test]
        public void testDuplicates()
        {
           AssertUniqueObjectContextLoading();
        }
    }
}
<!-- our DuplicateObjectTest-BeanohContext.xml bootstrap is as follows -->
<objects xmlns="http://www.springframework.net">
     <!-- load two contexts that might be defining duplicate object definitions -->
     <import resource="FirstDuplicate-context.xml" />
     <import resource="SecondDuplicate-context.xml" />
</objects>

Run this test, and it will fail if it finds duplicates.

c. Ignore Certain Object Definitions While Checking for Duplication

There are legitimate cases where we intentionally want to override some object definitions. An example would be to replace one data source with another for testing purposes, or we want to replace an old object definition pulled from an assembly that we cannot change.

Beanoh.NET can ignore those cases. All you need is to instruct your test fixture to exclude the object ids in question:

//our code will look like this
namespace SourceAllies.Beanoh.Duplicate
{
    [TestFixture]
    class IgnoreOneDuplicateObjectTest : BeanohTestCase
    {
        [Test]
        public void testDuplicates()
        {
            IgnoreDuplicateObjectNames("person");
            AssertUniqueObjectContextLoading();
        }
    }
}

The previous code ignores duplicate definitions of "person" while checking for duplicate beans. Of course, don't forget to name your bootstrap context appropriately as IgnoreOneDuplicateObjectTest-BeanohContext.xml.

d. Override a IDbProvider During Verification

Beanoh.NET provides a convenient method of overriding any IDbProvider object definitions that you might have in context. For example if you don't want to connect to your database during Beanoh.NET verifications use an IDbProvider.

All you need to do is to override that IDbProvider object definition with another one in the bootstrap context as follows (note that "DbProvider" is the object id of the IDbProvider we want to override and "AbstractBeanohDbProvider" is the id of the object definition provided by Beanoh.NET):

<objects xmlns="http://www.springframework.net">
   <!--
     This bootstrap context will load a context that requires a dbProvider which shouldn't be
     used in our tests.  Beanoh.NET provides a convenience data source definition that can be
     used to override such dependencies
   -->
  <import resource="DbProviderDefinition-context.xml"/>
  <object id="DbProvider" parent="AbstractBeanohDbProvider"/>
</objects>

Now, you can run your test AssertUniqueObjectContextLoading() calls without worrying that Beanoh.NET will fail due to a duplicate bean. That's why you have to define one bootstrap context and name it in a specific way so that Beanoh.NET can identify objects that were defined for testing.

Displaying Beanoh.NET logs

Beanoh.NET logs all messages using Common.Logging framework. To see those log messages, you need to add a reference to your favorite logging framework like log4net and also the appropriate connector framework that connects Common.Logging to your logging framework. In my case, it will be Common.Loggin.Log4Net.

Then your app.config needs to include the following lines and define the log4net configuration in a separate file log4net.config:

<configuration>
    ..................
  <!-- configuring Common.Logging logger -->
  <configSections>
    <sectionGroup name="common">
      <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
    </sectionGroup>
  </configSections>
  ...................
   <!-- connecting Common.Logging to log4net-->
  <common>
    <logging>
      <factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4net">
        <arg key="configType" value="FILE-WATCH" />
        <arg key="configFile" value="~/log4net.config" />
      </factoryAdapter>
    </logging>
  </common>
</configuration>

For more information on this, refer to Common.Logging documentation.

Dependencies

Beanoh.NET is designed to verifying Spring.NET contexts therefore it does have a dependency on Spring.NET. More specifically, Spring.Core, Spring.Aop and Spring.Data. Moreover, it also depends on Castle.Core for proxying, Common.Logging for logging, Moq for mocking and NUnit as the implementation framework of the Beanoh.NET test fixtures.

For Licensing information of those dependencies:

  1. Castle.Core:Apache License V2.0
  2. Common.Logging: Apache License V2.0
  3. Moq: BSD License
  4. NUnit
  5. Spring.NET: Apache License V2.0