7

I am pretty new to NUnit (and automated testing in general). I have recently done some Ruby On Rails work and noticed that in my test suite, when I create objects (such as a new user) and commit them during course of the suite, they are never committed to the database so that I can run the test over and over and not worry about that user already existing.

I am now trying to accomplish the same thing in NUnit, but I am not quite sure how to go about doing it. Do I create a transaction in the Setup and Teardown blocks? Thanks.

skaz
  • 21,962
  • 20
  • 69
  • 98
  • 1
    See this question http://stackoverflow.com/questions/321180/how-do-i-test-database-related-code-with-nunit – Mike Two Apr 28 '11 at 18:04

4 Answers4

4

Why would you talk to the database during unit-tests? This makes your unit-test to integration-tests by default. Instead, create wrappers for all database communication, and stub/mock it during unit-tests. Then you don't have to worry about database state before and after.

Now, if you are not willing to that level of refactoring: The problem with transactions is that you need an open connection. So, if your method targeted for testing handles all communication on its own, it is really difficult to inject a transaction that you can create at setup and roll back at teardown.

Morten
  • 3,778
  • 2
  • 25
  • 45
  • @Morten - I don't think I can do mock tests and I don't understand your second paragraph. Can you rephrase/elaborate? Thanks. – skaz Apr 28 '11 at 12:54
  • Maybe a solution... se other answer – Morten Apr 28 '11 at 15:33
  • @Morten - As a separate question - if you don't test the DB during these unit tests, what kind of test would I use to make sure that the db updated in the way I expected it to? Just an integration test? Thanks for your help. – skaz Apr 29 '11 at 14:44
  • 1
    @skaz Morten was trying to point out that tests that hit the DB aren't really unit tests but are integration tests in an NUnit test harness. They are still perfectly valid as integration tests for you to make sure your persistence layer works. He is saying remove the need to hit the database and test from your persistence layer up. Then you won't have to do the setup teardown for your db. It sounds like with ruby with its built in scaffolding was doing that for you hence why you asked the question. :) – ElvisLives May 02 '11 at 22:43
  • @ElvisLives - I get that those would be integration tests. I was just wondering if there is anything that tests "Data Access Only" that could be considered a unit type test, since it would only be for the data access layer. – skaz May 03 '11 at 12:11
  • 1
    @skaz, all those kinds of tests are integration tests, but there is absolutely nothing wrong about that. You just have to aknowledge it. Also, it would be a good idea not to bundle them with real unit tests, as you might mess with the database. Further, unit-test suites should be run really fast so you can run them all the time. Database communication as -- including handling of database state on setup and teardown -- does nothing for speed. So isolate those tests, and don't include them in unit-test runs. – Morten May 04 '11 at 13:21
  • To further add to this answer, unit tests only test a single unit, and are usually isolated and run completely in memory. This makes it feasible to run a full unit test suite before committing to ensure a change doesn't break any logic. Integration/System/User-Acceptance tests are slow by nature, and these should be run on the Continuous Integration build server, at less frequent rates. – jamiebarrow Apr 10 '12 at 11:24
  • Another option is using something such as TypeMock or Moles which run code in an environment that lets you dynamically mock out existing calls to services/databases/etc. These usually aren't free products though, but can enable mocking when you can't change the code. – jamiebarrow Apr 10 '12 at 11:25
4

Maybe you can use this. It is ugly, but perhaps it can work for you:

namespace SqlServerHandling
{
[TestFixture]
public sealed class TestTransactionRollBacks
{

    private string _connectionString = "Data Source = XXXDB; ; Initial Catalog = XXX; User Id = BLABLA; Password = BLABLA";
    private SqlConnection _connection;
    private SqlTransaction _transaction; 


    [SetUp]
    public void SetUp()
    {
        _connection = new SqlConnection(_connectionString);
        _transaction = _connection.BeginTransaction();
    }

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


    [Test]
    public void Test()
    {
        Foo foo = new Foo(_connection);

        object foo.Bar();



    }


}

internal class Foo
{
    private readonly SqlConnection _connection;
    object someObject = new object();
    public Foo(SqlConnection connection)
    {
        _connection = connection;
    }

    public object Bar()
    {
        //Do your Stuff
        return someObject;
    }
} 
razlebe
  • 7,134
  • 6
  • 42
  • 57
Morten
  • 3,778
  • 2
  • 25
  • 45
  • 2
    `TransactionScope` may be easier than `SqlTransaction` if your test does not have access to the `SqlConnection`. See http://stackoverflow.com/questions/321180/how-do-i-test-database-related-code-with-nunit – Mike Two Apr 28 '11 at 18:07
3

I agree with Morten's answer, but you might want to look at this very old MSDN Magazine article on the subject: Know Thy Code: Simplify Data Layer Unit Testing using Enterprise Services

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
0

I use SQLite for unit tests, using NHibenate. Even if you're not using NHibernate it should be possible to do. SQLite has an in memory mode, where you can create a database in memory and persist data there. It is fast, works well, and you can simply throw away and recreate the schema for each test or fixture as you see fit.

You can see the example from Ayende's blog for an overview of how its done. He is using NHibernate, but the concept should work with other ORM or a straight DAL as well.

Can Gencer
  • 8,822
  • 5
  • 33
  • 52