The following is some background info on this post. You can just skip to the question if you like:
In this excellent article (http://ayende.com/Blog/archive/2009/04/28/nhibernate-unit-testing.aspx) the author contends that "When using NHibernate we generally want to test only three things:
1) that properties are persisted,
2) that cascade works as expected
3) that queries return the correct result.
-) that mapping is complete & correct (implied)
My take is that he goes on to say that SQLite can and should be the unit test tool of choice to do all of the above. It should be noted that the author seems to be one of more experienced and skilled NHib developers out there, and though he doesn't expressly say so in the article, he implies in a question later that the domain can and should be handling some of SQLite's shortcomings.
QUESTION:
How do you use SQLite to test cascade relationships, especially given that it does not check foreign key constraints. How do you test your model to make sure foreign key constraints will not be a db issue.
Here are some units tests I came up with to test cascade behavior. The model is simply a Department that can have zero to many StaffMembers, with cascade set to NONE.
[Test]
public void CascadeSaveIsNone_NewDepartmentWithFetchedStaff_CanSaveDepartment()
{
_newDept.AddStaff(_fetchedStaff);
Assert.That(_newDept.IsTransient(), Is.True);
_reposDept.SaveOrUpdate(_newDept);
_reposDept.DbContext.CommitChanges();
Assert.That(_newDept.IsTransient(), Is.False);
}
[Test]
public void CascadeSaveIsNone_NewDepartmentWithFetchedStaff_CannotSaveNewStaff()
{
_newDept.AddStaff(_newStaff);
Assert.That(_newDept.IsTransient(), Is.True);
Assert.That(_newStaff.IsTransient(), Is.True);
_reposDept.SaveOrUpdate(_newDept);
_reposDept.DbContext.CommitChanges();
Assert.That(_newDept.IsTransient(), Is.False);
Assert.That(_newStaff.IsTransient(), Is.True);
}
[Test]
public void CascadeDeleteIsNone_FetchedDepartmentWithFetchedStaff_Error()
{
_fetchedDept.AddStaff(_fetchedStaff);
_reposDept.SaveOrUpdate(_fetchedDept);
_reposStaff.DbContext.CommitChanges();
_reposDept.Delete(_fetchedDept);
var ex = Assert.Throws<GenericADOException>(() => _reposDept.DbContext.CommitChanges());
Console.WriteLine(ex.Message);
Assert.That(ex.Message, Text.Contains("could not delete:"));
Console.WriteLine(ex.InnerException.Message);
Assert.That(ex.InnerException.Message, Text.Contains("The DELETE statement conflicted with the REFERENCE constraint"));
}
[Test]
public void Nullable_NewDepartmentWithNoStaff_CanSaveDepartment()
{
Assert.That(_newDept.Staff.Count(), Is.EqualTo(0));
var fetched = _reposDept.SaveOrUpdate(_newDept);
Assert.That(fetched.IsTransient(), Is.EqualTo(false));
Assert.That(fetched.Staff.Count(), Is.EqualTo(0));
}
The third test, ".._FetchedDepartmentWithFetchedStaff_Error" works against Sql Server, but not SQLite since the latter does not check foreign key constraints.
Here are tests for the other side of the relationship; a StaffMember can have one Department, with cascade set to NONE.
[Test]
public void CascadeSaveIsNone_NewStaffWithFetchedDepartment_CanSaveStaff()
{
_newStaff.Department = _fetchedDept;
_reposStaff.SaveOrUpdate(_newStaff);
_reposStaff.DbContext.CommitChanges();
Assert.That(_newStaff.Id, Is.GreaterThan(0));
}
[Test]
public void CascadeSaveIsNone_NewStaffWithNewDepartment_Error()
{
_newStaff.Department = _newDept;
Assert.That(_newStaff.IsTransient(), Is.True);
var ex = Assert.Throws<PropertyValueException>(() => _reposStaff.SaveOrUpdate(_newStaff));
Console.WriteLine(ex.Message);
Assert.That(ex.Message, Text.Contains("not-null property references a null or transient value"));
}
[Test]
public void CascadeDeleteIsNone_FetchedStaffWithFetchedDepartment_DeletesTheStaff_DoesNotDeleteTheDepartment()
{
_newStaff.Department = _fetchedDept;
_reposStaff.SaveOrUpdate(_newStaff);
_reposStaff.DbContext.CommitChanges();
_reposStaff.Delete(_newStaff);
Assert.That(_reposStaff.Get(_newStaff.Id), Is.Null);
Assert.That(_reposDept.Get(_fetchedDept.Id), Is.EqualTo(_fetchedDept));
}
[Test]
public void NotNullable_NewStaffWithUnknownDepartment_Error()
{
var noDept = new Department("no department");
_newStaff.Department = noDept;
var ex = Assert.Throws<PropertyValueException>(() => _reposStaff.SaveOrUpdate(_newStaff));
Console.WriteLine(ex.Message);
Assert.That(ex.Message, Text.Contains("not-null property references a null or transient"));
}
[Test]
public void NotNullable_NewStaffWithNullDepartment_Error()
{
var noDept = new Department("no department");
_newStaff.Department = noDept;
var ex = Assert.Throws<PropertyValueException>(() => _reposStaff.SaveOrUpdate(_newStaff));
Console.WriteLine(ex.Message);
Assert.That(ex.Message, Text.Contains("not-null property references a null or transient"));
}
These tests succed against Sql Server and SQLite. Can I trust the SQLite tests? Are these worthwhile tests?
Cheers,
Berryl
As i understand the article it is about testing the NHibernate Mapping. In my opinion this has nothing to do with db related issues but with testing the nhibernate attributes you set in your mapping. There is no need to assert that it is not possible to create invalid data: you only have to proof that your code creates the desired result and/or checks the things you want to check. You can test cascade, cascade-delete and delete-orphan. whatever you want the way you do it in the tests working with sqlite. But the third test tries to test the constraint, which is nothing nhibernate worries about.
If you want to test your Db contraints you should indeed use your production db and not sqlite. You could do it with or without hibernate but this has nothing to do with your mapping.
If you on the other hand really want a workarround for your Foreign Key tests with SQLite you could try to use this foreign_key_trigger_generator. I haven't tried but it seems to generate before-insert-triggers that assure the existance of the referenced Pk.
Maybe you could write a comment wheather this tool is usefull.
Related
Let's say I have the following method in a service:
private void deleteItems(List<Item> itemsToDelete) {
def sql = new Sql(dataSource)
itemsToDelete?.each { Item item ->
sql.execute("DELETE FROM owner_item WHERE item_id = ${item.id}")
item.delete(flush: true, failOnError: true)
flushDatabaseSession();
}
}
How do I create a test for this method in the ItemServiceSpec? When I try it, I get either a DataSource "Must specify a non-null Connection" error or a nullPointerException on sql.
This is my existing test.
#TestFor(ItemService)
#Mock([Item])
#Build([Item])
class SubjectServiceSpec extends Specification {
...
def "delete items"() {
given:
Item item1 = Item.build().save(flush: true)
Item item2 = Item.build().save(flush: true)
Item.count() == 2
DataSource mockDataSource = Mock()
service.dataSource = mockDataSource
1 * deleteItems
when:
service.deleteItems([item1, item2])
then:
Item.count() == 0
}
}
What you are trying to do here, is to mock a dependency (DataSource) of a dependency (Sql). This normally leads to a situation, where you a not 100% aware of how the Sql interacts with the DataSource Object. If Sql changes private interaction with the Datasource in a Version Update, you have to deal with the situation.
Instead of mocking a dependency of a dependency you should the Sql Class directly. For this, the sql has to be some kind of explicit dependency that you can receive via DI or a method parameter. In this case you can just mock the execute call like so (choosen the way of a Expando-Mock, but you could also use Map or the Mock Stuff from Spock):
given:
def sqlMock = new Expando()
sqlMock.execute = { return 'what ever you want or nothing, because you mock a delete operation' }
service.sql = sqlMock
when:
service.deleteItems([item1, item2])
then:
assertItemsAreDeletedAndTheOwnerAsWell()
Thinking about the whole testcase, there a two major problems in my opinion.
The first one is, when you ask yourself what kind of certainty do you really get here by mocking out the whole sql stuff. In this case, the only thing that you are doing here is to interact with the db. When you mock this thing out, then there is nothing anymore that you could test. There is not many conditional stuff or anything that should be backed up by a unit test. Due to this, I would suggest to write only integration spec for this test-case where you have something like a H2DB for testing purposes inplace.
The second thing is, that you actually don't need the Sql Manipulation at all. You can configure GORM and Hibernate in a way do a automatic and transparent deletion of the owner of the item, if the item is deleted. For this, look at the docs (especially the cascade part) from GORM or directly in the Hibernate docs.
To sum it up: use cascade: 'delete' together with a proper integration test and you have a high amount of certainty and less boilerplate code.
I am using NUnit for test units. I have my interface on the domain so i am ready to make implementation of those interfaces in the persistence layer. My question is how do you actually make the unit tests for testing those repositories ? i believe this isnt a good idea to test directly from the database. Ive heard poeple that are using SQLite but it is okay to use mocks instead ? why are the poeple using SQLite for in-memory database when you can provide a mock with actuals entities ?
Any example would be welcome too.
Note: This is intended to be repositories coded in C# that gonna use NHibernate and Fluent NHibernate as mapping.
Thanks.
It of course depends, but in most cases I'd say it's generally enough to just mock the repositories in your tests and using the in-memory SQLite database only to test your mappings (FluentNHibernate Persistence specification testing).
For the NUnit mappings tests with SQLite I'm using the following base class:
public abstract class MappingsTestBase
{
[SetUp]
public void Setup()
{
_session = SessionFactory.OpenSession();
BuildSchema(_session);
}
[TestFixtureTearDown]
public void Terminate()
{
_session.Close();
_session.Dispose();
_session = null;
_sessionFactory = null;
_configuration = null;
}
#region NHibernate InMemory SQLite Session
internal static ISession _session;
private static ISessionFactory _sessionFactory;
private static Configuration _configuration;
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
FluentConfiguration configuration = Fluently.Configure()
.Database(SQLiteConfiguration.Standard.InMemory().ShowSql)
.Mappings(m => m.FluentMappings
.AddFromAssemblyOf<NHibernateSession>())
.ExposeConfiguration(c => _configuration = c);
_sessionFactory = configuration.BuildSessionFactory();
}
return _sessionFactory;
}
}
private static void BuildSchema(ISession session)
{
SchemaExport export = new SchemaExport(_configuration);
export.Execute(true, true, false, session.Connection, null);
}
#endregion
}
An example mappings test class deriving from the above base class could then look like the following:
[TestFixture]
public class MappingsTest : MappingsTestBase
{
[Test]
public void Persistence_Employee_ShouldMapCorrectly()
{
Category employee = new PersistenceSpecification<Employee>(_session)
.CheckProperty(e => e.Id, 1)
.CheckProperty(e => e.FirstName, "John")
.CheckProperty(e => e.LastName, "Doe")
.VerifyTheMappings();
...
Assert.Equals(employee.FirstName, "John");
...
}
}
Personally I'd do functional testing of the repositories against an actual database (possibly SQL Express). You could run those tests in CI only once a day.
All the unit tests for other classes can safely assume that the repositories work and use mock repositories.
EDIT: The above presumes that your repositories are solely used for data access; they basically just use LINQ or HQL. Keep the business logic out of them!
When unit testing with NHibernate I will typically have tests that create and save an object, clear the session (session.Clear()) then retrieve the object from the database.
What's the equivalent of Session.Clear() with EF4?
Example test:
[Test]
public void Can_create_and_save_a_default_account()
{
var account = new Account();
_db.Accounts.AddObject(account);
_db.SaveChanges();
int id = account.AccountId;
// clear session
var fromDb = _db.Accounts.SingleOrDefault(x => x.AccountId == id);
Assert.IsNotNull(fromDb);
}
That will be recreating your DataContext-derived class (_db in your case).
You could mock your remote database with in-memory database. Here is example
SO after each test you will start from scratch.
I'm trying out TDD on a greenfield hobby app in ASP.NET MVC, and have started to get test methods such as the following:
[Test]
public void Index_GetRequest_ShouldReturnPopulatedIndexViewModel()
{
var controller = new EmployeeController();
controller.EmployeeService = GetPrePopulatedEmployeeService();
var actionResult = (ViewResult)controller.Index();
var employeeIndexViewModel = (EmployeeIndexViewModel)actionResult.ViewData.Model;
EmployeeDetailsViewModel employeeViewModel = employeeIndexViewModel.Items[0];
Assert.AreEqual(1, employeeViewModel.ID);
Assert.AreEqual("Neil Barnwell", employeeViewModel.Name);
Assert.AreEqual("ABC123", employeeViewModel.PayrollNumber);
}
Now I'm aware that ideally tests will only have one Assert.xxx() call, but does that mean I should refactor the above to separate tests with names such as:
Index_GetRequest_ShouldReturnPopulatedIndexViewModelWithCorrectID
Index_GetRequest_ShouldReturnPopulatedIndexViewModelWithCorrectName
Index_GetRequest_ShouldReturnPopulatedIndexViewModelWithCorrectPayrollNumber
...where the majority of the test is duplicated code (which therefore is being tested more than once and violates the "keep tests fast" advice)? That seems to be taking it to the extreme to me, so if I'm right as I am, what is the real-world meaning of the "one assert per test" advice?
It seems just as extreme to me, which is why I a also write multiple asserts per test. I already have >500 tests, writing just one assert per test would blow this up to at least 2500 and my tests would take over 10 minutes to run.
Since a good rest runner (such as Resharper's) lets you see the line where the test failed very quickly, you should still be able to figure out why a test failed with little effort. If you don't mind the extra effort, you can also add an assert description ("asserting payroll number correct"), so that you can even see this without even looking at the source code. With that, there is very little reason left to just one assert per test.
In his book The Art of Unit Testing, Roy Osherove talks about this subject. He too is in favour of testing only one fact in a unit test, but he makes the point that that doesn't always mean only one assertion. In this case, you are testing that given a GetRequest, the Index method ShouldReturnPopulatedIndexViewModel. It seems to me that a populated view model should contain an ID, a Name, and a PayrollNumber so asserting on all of these things in this test is perfectly sensible.
However, if you really want to split out the assertions (say for example if you are testing various aspects which require similar setup but are not logically the same thing), then you could do it like this without too much effort:
[Test]
public void Index_GetRequest_ShouldReturnPopulatedIndexViewModel()
{
var employeeDetailsViewModel = SetupFor_Index_GetRequest();
Assert.AreEqual(1, employeeDetailsViewModel.ID);
}
[Test]
public void Index_GetRequest_ShouldReturnPopulatedIndexViewModel()
{
var employeeDetailsViewModel = SetupFor_Index_GetRequest();
Assert.AreEqual("Neil Barnwell", employeeDetailsViewModel.Name);
}
[Test]
public void Index_GetRequest_ShouldReturnPopulatedIndexViewModel()
{
var employeeDetailsViewModel = SetupFor_Index_GetRequest();
Assert.AreEqual("ABC123", employeeDetailsViewModel.PayrollNumber);
}
private EmployeeDetailsViewModel SetupFor_Index_GetRequest()
{
var controller = new EmployeeController();
controller.EmployeeService = GetPrePopulatedEmployeeService();
var actionResult = (ViewResult)controller.Index();
var employeeIndexViewModel = (EmployeeIndexViewModel)actionResult.ViewData.Model;
var employeeDetailsViewModel = employeeIndexViewModel.Items[0];
return employeeDetailsViewModel;
}
It could also be argued that since these tests require the same setup, they should get their own fixture and have a single [SetUp] method. There's a downside to that approach though. It can lead to lots more unit test classes than actual, real classes which might be undesirable.
I use a helper class to contain the asserts. This keeps the test methods tidy and focused on what they're actually trying to establish. It looks something like:
public static class MvcAssert
{
public static void IsViewResult(ActionResult actionResult)
{
Assert.IsInstanceOfType<ViewResult>(actionResult);
}
public static void IsViewResult<TModel>(ActionResult actionResult, TModel model)
{
Assert.IsInstanceOfType<ViewResult>(actionResult);
Assert.AreSame(model, ((ViewResult) actionResult).ViewData.Model);
}
public static void IsViewResult<TModel>(ActionResult actionResult, Func<TModel, bool> modelValidator)
where TModel : class
{
Assert.IsInstanceOfType<ViewResult>(actionResult);
Assert.IsTrue(modelValidator(((ViewResult) actionResult).ViewData.Model as TModel));
}
public static void IsRedirectToRouteResult(ActionResult actionResult, string action)
{
var redirectToRouteResult = actionResult as RedirectToRouteResult;
Assert.IsNotNull(redirectToRouteResult);
Assert.AreEqual(action, redirectToRouteResult.RouteValues["action"]);
}
}
I'm trying to set up integration tests using the AbstractTransactionalJUnit4SpringContextTests base class. My goal is really simple: insert some data into the database using the simpleJdbcTemplate, read it back out using a DAO, and roll everything back. JPA->Hibernate is the persistence layer.
For my tests, I've created a version of the database that has no foreign keys. This should speed up testing by reducing the amount of fixture setup for each test; at this stage I'm not interested in testing the DB integrity, just the business logic in my HQL.
/* DAO */
#Transactional
#Repository("gearDao")
public class GearDaoImpl implements GearDao {
#PersistenceContext
private EntityManager entityManager;
/* Properties go here */
public Gear findById(Long id) {
return entityManager.find(Gear.class, id);
}
}
/* Test Page */
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"/com/dom/app/dao/DaoTests-context.xml"})
#TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false)
public class GearDaoImplTests extends AbstractTransactionalJUnit4SpringContextTests {
#Autowired
private GearDao gearDao;
#Test
#Rollback(true)
public void quickTest() {
String sql;
// fields renamed to protect the innocent :-)
sql = "INSERT INTO Gear (Gear_Id, fld2, fld3, fld4, fld5, fld6, fld7) " +
" VALUES (?,?,?,?,?,?,?)";
simpleJdbcTemplate.update(sql, 1L, 1L, 1L, "fld4", "fld5", new Date(), "fld7");
assertEquals(1L, simpleJdbcTemplate.queryForLong("select Gear_Id from Gear where Gear_Id = 1"));
System.out.println(gearDao);
Gear gear = gearDao.findById(1L);
assertNotNull("gear is null.", gear); // <== This fails.
}
}
The application (a Spring MVC site) works fine with the DAO's. What could be happening? And where would I begin to look for a solution?
The DAO somehow has a different dataSource than the simpleJdbcTemplate. Not sure how this would be, though, since there's only one dataSource defined in the DaoTests-context.xml file.
Hibernate requires all foreign key relations to be present in order to select out the Gear object. There are a couple of joins that are not present since I'm hardcoding those in fld2/fld3/fld4.
The DAO won't act on the uncommitted data. But why would the simpleJdbcTemplate honor this? I'd assume they both do the same thing.
Underpants gnomes. But where's the profit?
What a difference a couple hours of sleep makes. I woke up and thought "I should check the logs to see what query is actually being executed." And of course it turns out that hibernate was configured to generate some inner joins for a few of the foreign keys. Once I supplied those dependencies it worked like a charm.
I'm loving the automatic rollback on every test concept. Integration tests, here I come!