Skip to content

Persistence tests

xhafan edited this page Dec 17, 2018 · 13 revisions

To make sure entities are able to correctly persist into a database, it's a good practise to add entity persistence tests. These tests will give a developer confidence that the entity persistence still works correctly when modifying entities.

To add a new domain entity persistence test, create a new class library project, add CoreDdd.Nhibernate.TestHelpers nuget package, and create a new test class. Here is an example of a persistence test for a domain entity Ship, using NUnit testing framework (please follow this article for NUnit when targeting .NET Core or .NET Standard) and Shouldly assertion framework :

using CoreDdd.Nhibernate.TestHelpers;
using CoreDdd.Nhibernate.UnitOfWorks;
using CoreDddSampleWebAppCommon;
using CoreDddSampleWebAppCommon.Domain;
using NUnit.Framework;
using Shouldly;

namespace CoreDddSample.PersistenceTests
{
    [TestFixture]
    public class when_persisting_ship
    {
        private NhibernateUnitOfWork _unitOfWork;
        private Ship _newShip;
        private Ship _persistedShip;

        [SetUp]
        public void Context()
        {
            _unitOfWork = new NhibernateUnitOfWork(new CoreDddSampleNhibernateConfigurator());
            _unitOfWork.BeginTransaction();

            _newShip = new Ship("ship name", tonnage: 23.4m);

            _unitOfWork.Save(_newShip); // save entity into DB -> send INSERT SQL statement into DB

            _unitOfWork.Clear(); // clear NHibernate session so the following SQL SELECT would not load the cached entity version from the session, but would query the database

            _persistedShip = _unitOfWork.Get<Ship>(_newShip.Id);
        }

        [Test]
        public void ship_can_be_retrieved()
        {
            _persistedShip.ShouldNotBeNull();
        }

        [Test]
        public void persisted_ship_id_matches_the_saved_ship_id()
        {
            _persistedShip.ShouldBe(_newShip);
        }

        [Test]
        public void ship_data_are_persisted_correctly()
        {
            _persistedShip.Name.ShouldBe("ship name");
            _persistedShip.Tonnage.ShouldBe(23.4m);
        }

        [TearDown]
        public void TearDown()
        {
            _unitOfWork.Rollback();
        }
    }
}

This persistence test creates a new aggregate root domain entity Ship, saves it into a database and loads it from the database, and checks that the persisted entity matches the saved entity. It uses NHibernate configurator class CoreDddSampleNhibernateConfigurator. Next, add NHibernate configuration file hibernate.cfg.xml into the project, SQLite example:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>

    <property name="connection.connection_string">Data Source=CoreDddSamplePersistenceTests.db</property>
    <property name="dialect">NHibernate.Dialect.SQLiteDialect</property>
    <property name="connection.driver_class">NHibernate.Driver.SQLite20Driver</property>
    <property name="connection.release_mode">on_close</property>

    <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
    <property name="show_sql">true</property>
    <property name="proxyfactory.factory_class">NHibernate.Bytecode.DefaultProxyFactoryFactory, NHibernate</property>
    <property name="transaction.use_connection_on_system_prepare">false</property> <!-- set transaction.use_connection_on_system_prepare to 'false' when using .NET 4.6.1+ or .NET Standard 2.0+, NHibernate 5.1.0+, more info here https://github.com/npgsql/npgsql/issues/1985#issuecomment-397266128 ; remove this line for previous NHibernate versions -->

  </session-factory>
</hibernate-configuration>

In hibernate.cfg.xml properties, set Build Action to Content and Copy to Output Directory to Copy if newer. Add SQLite database driver package System.Data.SQLite.Core into the project. For other database hibernate.cfg.xml examples and database driver installation, please have a look here.

The last step is to create the test database. There are several options:

  1. Use an existing database for testing. The disadvantage is that the existing database might be large, and the persistence tests executed on it might be slow.
  2. Create an empty test database before each test run. This can be done using NHibernate schema export feature.
  3. Build an empty test database. You can delete data from an existing database to make the persistence tests run faster, or you can build a database from scratch using SQL scripts and DatabaseBuilder.

This tutorial will use option 2 - using NHibernate's schema export feature to re-create the database before each test run. Add a new class called RunOncePerTestRun into the project with the following content:

using System.Data.SQLite;
using CoreDdd.Nhibernate.DatabaseSchemaGenerators;
using CoreDddSampleWebAppCommon;
using NUnit.Framework;

namespace CoreDddSample.PersistenceTests
{
    [SetUpFixture]
    public class RunOncePerTestRun
    {
        [OneTimeSetUp]
        public void SetUp()
        {
            _CreateDatabase();
        }

        private void _CreateDatabase()
        {
            using (var nhibernateConfigurator = new CoreDddSampleNhibernateConfigurator(shouldMapDtos: false)) // shouldMapDtos: false -> make sure dto database views are not created as tables
            {
                var configuration = nhibernateConfigurator.GetConfiguration();
                var connectionString = configuration.Properties["connection.connection_string"];

                using (var connection = new SQLiteConnection(connectionString)) // for SQL server, use SqlConnection, for PostgreSQL, use NpgsqlConnection
                {
                    connection.Open();
                    new DatabaseSchemaCreator().CreateDatabaseSchema(nhibernateConfigurator, connection);
                }
            }
        }
    }
}

This code uses application's NHibernate configurator CoreDddSampleNhibernateConfigurator and CoreDdd's DatabaseSchemaCreator, which will build a SQL script from application's domain entities, and will execute the script to create a test database.

Now it should be possible to run the Ship entity persistence test. The code samples above are available here.

You can’t perform that action at this time.