Skip to content

Persistence tests

xhafan edited this page Oct 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 and Shouldly assertion framework:

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

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

        [SetUp]
        public void Context()
        {
            _p = new PersistenceTestHelper(new CoreDddSampleNhibernateConfigurator());
            _p.BeginTransaction();

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

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

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

            _persistedShip = _p.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()
        {
            _p.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 also uses existing NHibernate configurator class (CoreDddSampleNhibernateConfigurator) which is part of the application project. 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 into the project (version 1.0.108 needs to be manually installed via command Install-Package System.Data.SQLite.Core -Version 1.0.108 from Package Manager Console: Tools -> Nuget Package Manager -> Package Manager Console; current latest version 1.0.109.1 is broken). 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 (e.g. CoreDddSampleNhibernateConfigurator), which will build a SQL script from application's domain entities, and will execute the script to create a test database.

If targeting .NET Core and using NUnit, don't forget to follow this tutorial.

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

Clone this wiki locally