Hilo Unit Test

58 views
Skip to first unread message

SirSirAaron

unread,
Jun 8, 2012, 3:35:11 PM6/8/12
to nhu...@googlegroups.com
When I am running unit tests I don't want increment the hi when a session factory is created. Does anyone know a way in which to prevent this behavior? Additionally, it would be great if I could set the session factory's hi manually without touching the database. 

Jason Meckley

unread,
Jun 8, 2012, 5:02:49 PM6/8/12
to nhu...@googlegroups.com
IIRC hi is created the first time the entity is requested, not when the factory is created. in a unit test this could occur at the same time. In either case the high value must be created. it's stored in the db to ensure uniqueness. without this there is a potential for duplicate keys. NH protects the dev from this. What you described is by design and not meant to be altered. NH is meant to touch a DB. if you don't want to touch a physical db use a sqlite in-memory db. they are lighting fast compared to a file DB.

SirSirAaron

unread,
Jun 8, 2012, 5:51:51 PM6/8/12
to nhu...@googlegroups.com
Thanks for the super quick reply Jason. I think you may be right regarding the time at which nhibernate increments the "hi". I understand the basics of hilo generation and the necessity for a table to store the "hi" for synchronization across multiple session factories. That being said, I understand what I'm doing is contrary to its design and I'm purposefully looking for a hack or another way of approaching the problem.

At the moment I am using fluent nhibernate's persistencespecification tests for each of my domain objects which will eventually grow to hundred or so tests. Additionally, I create a new session factory for each test in an effort to achieve isolation. I have multiple developers running these tests daily and I would prefer not to increment the "hi". 

Right now I have a max_lo = 100
(2^31[size of int])/100[max_lo]/100[number of unit tests] =  214 748 

Lets say I have 50 developers running these tests 10 times a day then I'll be out of space after a year so:
(2^31-1)/100/100/50[developers]/10[number of times test run]/365 = 1.17

Fran Knebels

unread,
Jun 8, 2012, 6:33:45 PM6/8/12
to nhu...@googlegroups.com

Why not have nhibernate regenerate the schema for every unit test. 

Now you've got total isolation because the entire schema is dropped after every test.

--
You received this message because you are subscribed to the Google Groups "nhusers" group.
To view this discussion on the web visit https://groups.google.com/d/msg/nhusers/-/02Ts1K8I4YsJ.
To post to this group, send email to nhu...@googlegroups.com.
To unsubscribe from this group, send email to nhusers+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nhusers?hl=en.

Alex Norcliffe

unread,
Jun 8, 2012, 6:40:35 PM6/8/12
to nhu...@googlegroups.com
+1, if you're reusing the database between fixture runs your tests can quickly become non-deterministic.
 
To speed things up for you, is SqlLite in-memory an option for your scenario?

SirSirAaron

unread,
Jul 23, 2012, 9:20:42 PM7/23/12
to nhu...@googlegroups.com, emailmes...@googlemail.com
Thank you for your suggestions! I decided to recreate the table each time as suggested. I sometimes share a DB with other developers so I decided create a unique key table with a partial uuid for each test to avoid race conditions. Here is my code if anyone is curious:

public class UnitTestableHiloIdConvention : IIdConvention
{
static UnitTestableHiloIdConvention()
{
UniqueTableIdentifier = Guid.NewGuid();
}

private static readonly Guid UniqueTableIdentifier;

public static string UniqueKeyUnitTestTableName
{
get
{
//nhibernate unique key unit test plus partial uuid (oracle has a max table name of 30 characters)
return "hibernate_uk_ut_" + UniqueTableIdentifier.ToString().Substring(0, 14).Replace('-', '_');
}
}

public void Apply(IIdentityInstance instance)
{
string tableName = AppInfo.IsInUnitTestMode
  ? UnitTestableHiloIdConvention.UniqueKeyUnitTestTableName
  : "hibernate_unique_key";
instance.GeneratedBy.HiLo(tableName, "next_hi", "100");
}
}

public class DatabaseTests
{
private void CreateHiloTable(int initialHi = 0)
{
string createQuery = String.Format("CREATE TABLE [{0}]( "
+ "[next_hi] [int] NOT NULL, "
+ "CONSTRAINT [PK_{0}] PRIMARY KEY CLUSTERED ([next_hi] ASC) "
  + ")"
  , UnitTestableHiloIdConvention.UniqueKeyUnitTestTableName);
ExecuteSqlQuery(createQuery);
string insertQuery = String.Format("INSERT INTO [{0}] VALUES({1});"
  , UnitTestableHiloIdConvention.UniqueKeyUnitTestTableName, initialHi);
ExecuteSqlQuery(insertQuery);
}

private void DeleteHiloTable()
{
//check if table exists before deleting it 
string deleteQuery = String.Format("IF OBJECT_ID('[{0}]','U') IS NOT NULL "
  + "DROP TABLE [{0}];"
  , UnitTestableHiloIdConvention.UniqueKeyUnitTestTableName);
ExecuteSqlQuery(deleteQuery);
}

private void ExecuteSqlQuery(string query)
{
using (ISession session = SessionFactory.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.CreateSQLQuery(query).ExecuteUpdate();
transaction.Commit();
}
}

[SetUp]
public void SetUp()
{
CreateHiloTable();
Session = SessionFactory.OpenSession();
NHibernate.Context.CurrentSessionContext.Bind(Session);

//evict cached data
Session.Clear();
Transaction = Session.BeginTransaction();
}

[TearDown]
public void TearDown()
{
Transaction.Rollback();
Transaction.Dispose();
Session.Close();
Session.Dispose();

DeleteHiloTable();
}
}

On Friday, June 8, 2012 6:40:35 PM UTC-4, Alex Norcliffe wrote:
+1, if you're reusing the database between fixture runs your tests can quickly become non-deterministic.
 
To speed things up for you, is SqlLite in-memory an option for your scenario?
 
On 8 June 2012 23:33, Fran Knebels <fkne...@gmail.com> wrote:

Why not have nhibernate regenerate the schema for every unit test. 

Now you've got total isolation because the entire schema is dropped after every test.

On Jun 8, 2012 5:51 PM, "SirSirAaron" <theyell...@gmail.com> wrote:
Thanks for the super quick reply Jason. I think you may be right regarding the time at which nhibernate increments the "hi". I understand the basics of hilo generation and the necessity for a table to store the "hi" for synchronization across multiple session factories. That being said, I understand what I'm doing is contrary to its design and I'm purposefully looking for a hack or another way of approaching the problem.

At the moment I am using fluent nhibernate's persistencespecification tests for each of my domain objects which will eventually grow to hundred or so tests. Additionally, I create a new session factory for each test in an effort to achieve isolation. I have multiple developers running these tests daily and I would prefer not to increment the "hi". 

Right now I have a max_lo = 100
(2^31[size of int])/100[max_lo]/100[number of unit tests] =  214 748 

Lets say I have 50 developers running these tests 10 times a day then I'll be out of space after a year so:
(2^31-1)/100/100/50[developers]/10[number of times test run]/365 = 1.17


On Friday, June 8, 2012 5:02:49 PM UTC-4, Jason Meckley wrote:
IIRC hi is created the first time the entity is requested, not when the factory is created. in a unit test this could occur at the same time. In either case the high value must be created. it's stored in the db to ensure uniqueness. without this there is a potential for duplicate keys. NH protects the dev from this. What you described is by design and not meant to be altered. NH is meant to touch a DB. if you don't want to touch a physical db use a sqlite in-memory db. they are lighting fast compared to a file DB.

On Friday, June 8, 2012 3:35:11 PM UTC-4, SirSirAaron wrote:
When I am running unit tests I don't want increment the hi when a session factory is created. Does anyone know a way in which to prevent this behavior? Additionally, it would be great if I could set the session factory's hi manually without touching the database. 

--
You received this message because you are subscribed to the Google Groups "nhusers" group.
To view this discussion on the web visit https://groups.google.com/d/msg/nhusers/-/02Ts1K8I4YsJ.
To post to this group, send email to nhu...@googlegroups.com.
To unsubscribe from this group, send email to nhusers+unsubscribe@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/nhusers?hl=en.

--
You received this message because you are subscribed to the Google Groups "nhusers" group.
To post to this group, send email to nhu...@googlegroups.com.
To unsubscribe from this group, send email to nhusers+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages