Hibernate and NHibernate

Building Enterprise Frameworks – Testing and Mock Objects

0

This is the third installment of the “Building Enterprise Frameworks” series, which is the evolving design of an enterprise framework. In the series introduction, we presented a problem faced by many enterprise software teams and delivered a plan. The previous blog entry introduced the preliminary data access layer and domain model, which are a collection of abstractions forming a unified framework or infrastructure. In this blog entry, we refactor the data access layer and build the supporting unit tests.

Before covering testing, we will refactor the Repository introduced in the previous installment. At this time, we will eliminate the RepositoryBase abstract class. After testing and coding additional NHibernateRepositoryBase features, this class provided no immediate value to the enterprise framework. The abstract class was moved to the Framework Repository folder, which was vacated by the previous RepositoryBase. We also refactored the Generic interfaces and classes, which better aligns with our technical design and objectives. The following is the revised Framework project structure.

The following is the IRepository interface, which defines the required Repository implementation methods. As discussed in the previous installment, these are the basic Create-Read-Update-Delete (CRUD) operations.

01
using System;
02
using System.Collections.Generic;
03
using Joemwalton.Framework.Domain;
04
 
05
namespace Joemwalton.Framework.Data.Repository
06
{
07
    public interface IRepository<TEntity, TId>
08
        where TEntity : IEntity<TId>
09
    {
10
        void Save(TEntity entity);
11
        void Remove(TEntity entity);
12
        TEntity FindById(TId id);
13
        List<TEntity> FindAll();
14
    }
15
}

Since we eliminated the RepositoryBase abstract class, the NHibernateRepositoryBase will replace the method implementation for our NHibernate base class. The next installment of the “Building Enterprise Frameworks” series will focus on NHibernate and IoC, so the details of the design will not be discussed here – including session and transaction management. The base class will include the CRUD method implementation, so the concrete Repository implementations remain focused on providing domain specific data services. Basically…eliminating redundant code!

01
using System;
02
using System.Collections.Generic;
03
using NHibernate;
04
using NHibernate.Criterion;
05
using Joemwalton.Framework.Data.Repository;
06
using Joemwalton.Framework.Domain;
07
 
08
namespace Joemwalton.Framework.Data.NHibernate
09
{
10
    public abstract class NHibernateRepositoryBase<TEntity, TId> 
11
        : IRepository<TEntity, TId>
12
        where TEntity : IEntity<TId>
13
    {
14
        private ISessionFactory _sessionFactory;
15
 
16
        /// <summary>
17
        /// NHibernate Session Factory
18
        /// </summary>
19
        public ISessionFactory SessionFactory
20
        {
21
            protected get { return _sessionFactory; }
22
            set { _sessionFactory = value; }
23
        }
24
 
25
        /// <summary>
26
        /// Get current active session
27
        /// </summary>
28
        protected ISession CurrentSession
29
        {
30
            get { return this.SessionFactory.GetCurrentSession(); }
31
        }
32
 
33
        public TEntity FindById(TId id)
34
        {
35
            return this.CurrentSession.Get<TEntity>(id);
36
        }
37
 
38
        public List<TEntity> FindAll()
39
        {
40
            ICriteria query = this.CurrentSession.CreateCriteria(typeof(TEntity));
41
            return (List<TEntity>)query.List<TEntity>();
42
        }
43
 
44
        public void Save(TEntity entity)
45
        {
46
            using (ITransaction transaction = this.CurrentSession.BeginTransaction())
47
            {
48
                this.CurrentSession.SaveOrUpdate(entity);
49
                transaction.Commit();
50
            }
51
        }
52
 
53
        public void Remove(TEntity entity) 
54
        {
55
            using (ITransaction transaction = this.CurrentSession.BeginTransaction())
56
            {
57
                this.CurrentSession.Delete(entity);
58
                transaction.Commit();
59
            }
60
        }
61
    }
62
}

We are finished with the refactoring, so our attention shifts to building unit tests for our framework. As you noticed, we have no concrete classes – this is by design. So…how do we test interface and abstract classes? Why are we creating interfaces again?

The answer to question 2 is loose coupling and ability to test classes in isolation. This also promotes our core design principles and the supporting design patterns, which we covered in the “How to design and build better software for tomorrow?” series.

How do we test interface and abstract classes? The best approach is creating mock objects that implement the interfaces and inherit the base classes. The mock objects will mimic our concrete implementations, but with no real business logic. The following is the Framework Test project structure, which will contain our unit test and mock classes. 

The following is the EntityMock class, which inherits the EntityBase and defines the Generic type as int. This will represent the Id property type.

01
using System;
02
using Joemwalton.Framework.Domain;
03
 
04
namespace Joemwalton.Framework.Test.Mocks
05
{
06
    public class EntityMock 
07
        : EntityBase<int>
08
    {
09
        public EntityMock() 
10
        {
11
            this.Id = 1;
12
            Validate();
13
        }
14
 
15
        protected override void Validate()
16
        {
17
            this.FailedValidations.Clear();
18
            if (this.Id == 1)
19
                FailedValidations.Add("Testing");
20
        }
21
    }
22
}

The mock object contains an implementation for the constructor and Validate method, since the EntityBase handled the Id property. The following is the RepositoryMock class, which will focus on the relevant method implementation to support the framework.

01
using System;
02
using System.Collections.Generic;
03
using Joemwalton.Framework.Data.Repository;
04
using Joemwalton.Framework.Test.Mocks;
05
 
06
namespace Joemwalton.Framework.Test.Mocks
07
{
08
    public class RepositoryMock 
09
        : IRepository<EntityMock, int>
10
    {
11
        public void Save(EntityMock entity)
12
        {
13
            throw new NotImplementedException();
14
        }
15
 
16
        public void Remove(EntityMock entity)
17
        {
18
            throw new NotImplementedException();
19
        }
20
 
21
        public EntityMock FindById(int id)
22
        {
23
            return new EntityMock();
24
        }
25
 
26
        public List<EntityMock> FindAll()
27
        {
28
            return new List<EntityMock> { new EntityMock() };
29
        }
30
    }
31
}

The mock object implements the IRepository interface, where the contract defines the basic CRUD operations. The method implementation is not important, since we are not testing the ability of the Repository to retrieve or persist objects. The IRepository is a Generic interface, so the concrete entity type definition is required.

With the mock objects available, we can build our unit tests for the entity and Repository framework. In the following, the unit tests are based on the Microsoft Visual Studio Test libraries, although you can also build your tests with the open source NUnit framework. In either case, the goal is building the necessary unit tests for the framework.

01
using System;
02
using Microsoft.VisualStudio.TestTools.UnitTesting;
03
using Joemwalton.Framework.Data.Repository;
04
using Joemwalton.Framework.Test.Mocks; 
05
 
06
namespace Framework.Test
07
{
08
    [TestClass]
09
    public class EntityTest
10
    {
11
        public EntityTest() { }
12
 
13
        public TestContext TestContext { get; set; }
14
 
15
        [TestMethod]
16
        public void GetIdTest()
17
        {
18
            EntityMock mock = new EntityMock();
19
            int expected = 1;
20
            Assert.AreEqual(expected, mock.Id);
21
        }
22
 
23
        [TestMethod]
24
        public void SetIdTest()
25
        {
26
            EntityMock mock = new EntityMock();
27
            int expected = 2;
28
            mock.Id = expected;
29
            Assert.AreEqual(expected, mock.Id);
30
        }
31
 
32
        [TestMethod]
33
        public void GetFailedValidationsTest()
34
        {
35
            EntityMock mock = new EntityMock();
36
            Assert.AreEqual(1, mock.GetFailedValidations().Count);
37
            string expected = "Testing";
38
            Assert.AreEqual(expected, mock.GetFailedValidations()[0]);
39
        }
40
    }
41
}

In the above EntityTest class, we decorate the class with TestClass and test methods with TestMethod attributes. The test methods create an instance of the EntityMock and validate the results, although the EntityMock instantiation can also be accomplished during the test class initialization and shared for all test methods. The following is the RepositoryTest, which follows the same approach as the EntityTest.

01
using System;
02
using System.Text;
03
using System.Collections.Generic;
04
using System.Linq;
05
using Microsoft.VisualStudio.TestTools.UnitTesting;
06
using Joemwalton.Framework.Test.Mocks;
07
 
08
namespace Joemwalton.Framework.Test
09
{
10
    [TestClass]
11
    public class RepositoryTest
12
    {
13
        public RepositoryTest() { }
14
 
15
        public TestContext TestContext { get; set; }
16
 
17
        [TestMethod]
18
        [ExpectedException(typeof(NotImplementedException))]
19
        public void SaveTest()
20
        {
21
            RepositoryMock mock = new RepositoryMock();
22
            mock.Save(new EntityMock());
23
        }
24
 
25
        [TestMethod]
26
        [ExpectedException(typeof(NotImplementedException))]
27
        public void RemoveTest()
28
        {
29
            RepositoryMock mock = new RepositoryMock();
30
            mock.Remove(new EntityMock());
31
        }
32
 
33
        [TestMethod]
34
        public void FindByIdTest()
35
        {
36
            RepositoryMock mock = new RepositoryMock();
37
            EntityMock expected = new EntityMock();
38
            EntityMock actual = mock.FindById(1);
39
            Assert.AreEqual(expected.Id, actual.Id);
40
        }
41
 
42
        [TestMethod]
43
        public void FindAllTest()
44
        {
45
            RepositoryMock mock = new RepositoryMock();
46
            EntityMock expected = new EntityMock();
47
            List<EntityMock> actual = mock.FindAll();
48
            Assert.AreEqual(1, actual.Count);
49
            Assert.AreEqual(expected.Id, actual[0].Id);
50
        }
51
    }
52
}

The next step is run the tests. This is simple using Visual Studio, which includes several convenient options depending on your version. The Test menu or toolbar will provide an option to “Run All Tests in Solution”, which will run the tests and report the results. Alternatively, the Test View window will provide another interface to run tests.

In the Test View, you can highlight all tests and select “Run Selection” from the toolbar. This will execute the unit tests and display the information in the Test Results window, which appears below.

As you can see, the Test View window also provides several options to run and debug tests. Unfortunately, you will lose these handy features with an open source or non-Microsoft test tool.

In summary, we created mock objects for our domain model and Repository framework. Once we developed the mock objects, we created unit tests to ensure the relevant base implementation is working as expected. As we refactor the framework, the unit tests will ensure changes do not introduce bugs or break existing features. The introduction of a Continuous Integration (CI) process will further extend the test value with an event-driven build and test execution process. This can be accomplished using Microsoft Team Foundation Server (TFS), CruiseControl.NET, Team City or several other CI products.

What’s next? The next installment will focus on NHibernate including the SessionFactory, mapping and transaction management. This will segue into the IoC and Spring.NET support, which will provide many time saving NHibernate features.

Finally, I received several requests for a Java implementation. So…I am planning to build a Java equivalent enterprise framework solution. Thanks again for your comments and suggestions!!!!

Previous: Building Enterprise Frameworks – Data and Domain

Thinking Enterprise Architecture

Building Enterprise Frameworks – Data and Domain

0

In the previous blog entry “Thinking Enterprise Architecture”, I presented the background for a series focusing on Enterprise Architecture. Previously, we discussed the core design principles for software development. We also introduced several design patterns to satisfy the core principles. The concepts were applied to several technologies and demonstrated using Inversion of Control (IoC), Model-View-Controller (MVC) and Windows Communication Foundation (WCF). Since the core design principles and design patterns are not framework or language specific, the “Part VI: Brick Design – How to design and build better software for tomorrow?” article was a Java implementation of the Contact Manager application.

In this entry, I will provide the preliminary enterprise framework core components supporting the domain model and data tier. I will emphasize the word preliminary, because the framework will evolve and refactoring will be required to satisfy our objectives. I will loosely base the framework on the design built by the team introduced in the background entry, since they prefer not to share all design and implementations. The project will be based on my standard Contact Manager application. Basically, we are separating the common components and establishing a framework to build enterprise applications.

First, we create a new project as a class library for the common enterprise framework. The project contains the Data and Model root folders, which are collections of interface and abstract classes. These are not our concrete implementations, but the shared objects that our enterprise projects reference.

The Domain folder includes the IEntity interface and the abstract EntityBase class. All domain model concrete classes should implement IEntity. The interface is our contract, so this should drive the implementations within an interface-based system. The interface includes the Id property, which is the only domain object property that should be common for all concrete implementations.

1
using System;
2
 
3
namespace Joemwalton.Framework.Domain
4
{
5
    public interface IEntity<TId>
6
    {
7
        TId Id { get; set; }
8
    }
9
}

We elected to create a Generic interface, so we can define the types at run-time and not design-time. In this case, our Id property type is unknown. The implementation will define the type, so we are not forced to commit in the contract.

The EntityBase is an abstract class, which serves as a base class to define shared behavior for an implementation to inherit. This class is providing the implementation for the common entity Id property and validation logic. In this domain-driven design, we are encapsulating the business rules for validating the domain object. The Validate method is abstract, since only the concrete implementation would be aware of the validation logic required for the domain object. As we refactor the framework classes, the following will change to reflect our technical design.

01
using System;
02
using System.Collections.Generic;
03
 
04
namespace Joemwalton.Framework.Domain
05
{
06
    public abstract class EntityBase<TEntity,TId> 
07
        : IEntity<TId>
08
        where TEntity : IEntity<TId>
09
    {
10
        public  TId Id { get; set; }
11
 
12
        private List<string> _failedValidations = new List<string>();
13
        protected List<string> FailedValidations 
14
        {
15
            get { return _failedValidations; } 
16
        }
17
 
18
        public List<string> GetFailedValidations()
19
        {
20
            _failedValidations.Clear();
21
            Validate();
22
            return _failedValidations;
23
        }
24
 
25
        protected abstract void Validate();
26
    }
27
}

The next step is the skeleton design for the data tier, which includes the data access tier or repository. The repository is a memory-based domain collection, which is responsible for persisting and retrieving the domain objects. We will also build an interface and base class to support the concrete repository implementations. The IRepository interface is the contract, which includes methods for the standard Create-Read-Update-Delete (CRUD) operations. At this point, we would like all repository implementations to support the basic operations – Save, FindById, FindAll, Update and Delete. The concrete implemenations could include additional methods, which provide additional operations.

01
using System;
02
using System.Collections.Generic;
03
using Joemwalton.Framework.Domain;
04
 
05
namespace Joemwalton.Framework.Data.Repository
06
{
07
    public interface IRepository<TEntity,TId>
08
        where TEntity : IEntity<TId>
09
    {
10
        void Save(TEntity entity);
11
        void Remove(TEntity entity);
12
        TEntity FindById(TId id);
13
        List<TEntity> FindAll();
14
    }
15
}

Since our domain object type is unknown at design-time, we use generics to allow run-time assignments. The where clause is included as a contraint, so the run-time type must be IEntity. The TEntity represents the run-time domain object. The following RepositoryBase abstract class is a placeholder, so this will also be refactored as our design evolves.

01
using System;
02
using System.Collections.Generic;
03
using NHibernate;
04
using Joemwalton.Framework.Domain;
05
 
06
namespace Joemwalton.Framework.Data.Repository
07
{
08
    public abstract class BaseRepository<TEntity,TId> 
09
        : IRepository<TEntity,TId>
10
        where TEntity : IEntity<TId>
11
    {
12
        public void Remove(TEntity entity) { }
13
 
14
        public void Save(TEntity entity) { }
15
 
16
        public TEntity FindById(TId id)
17
        {
18
            return default(TEntity);
19
        }
20
 
21
        public List<TEntity> FindAll()
22
        {
23
            return new List<TEntity>() { default(TEntity) };
24
        }
25
    }
26
}

Next, the Data.NHibernate folder contains the NHibernateRepositoryBase abstract class. This class contains NHibernate implementation code including the SessionFactory. Since we also selected Spring.NET, the Spring framework Object-Relational Mapping (ORM) modules provides the plumbing for this support. The IoC container provides the features to simplify the configuration, NHibernate session and enterprise transaction management. This class will also require refactoring as the features and implementations are discovered, but the following is a start.

01
using System;
02
using NHibernate;
03
using Joemwalton.Framework.Data.Repository;
04
using Joemwalton.Framework.Domain;
05
 
06
namespace Joemwalton.Framework.Data.NHibernate
07
{
08
    public abstract class NHibernateRepositoryBase<TEntity,TId> 
09
        : BaseRepository<TEntity,TId>
10
        where TEntity : IEntity<TId>
11
    {
12
        private ISessionFactory sessionFactory;
13
 
14
        /// <summary>
15
        /// Session factory
16
        /// </summary>
17
        public ISessionFactory SessionFactory
18
        {
19
            protected get { return sessionFactory; }
20
            set { sessionFactory = value; }
21
        }
22
 
23
        /// <summary>
24
        /// Get current active session
25
        /// </summary>
26
        protected ISession CurrentSession
27
        {
28
            get { return sessionFactory.GetCurrentSession(); }
29
        }
30
    }
31
}

In summary, the above are the draft enterprise framework classes and refactoring will be required in the future installments of the series. In the next entry, we will build tests including the mock objects for our abstractions. Once the enterprise framework is established, we will create a Contact Manager application. So…stay tuned for the next article in this series!

Next: Building Enterprise Frameworks - Testing and Mock Objects

Previous: Thinking Enterprise Architecture

Go to Top