4

I have some integration tests around stored procs. Typically I do the test setup using Dapper. This is fine for simple cases, but in some cases to setup up the system correctly it would be far simpler to call the necessary stored procs. It would be simpler because some entities have many relationships and constraints and replicating that in Dapper is time consuming, plus if I change the system I have to then change my Dapper test setup code too.

Is it a good idea to use the system to setup the system to test or should I keep the setup of the system independent of the system?

I've added a simple code sample, below, (not representative of my actual system) to help clarify what I mean. In the first test I'm checking that CreatePerson actually adds an entity into the Person table. In the second test I use the method I just tested, CreatePerson, to setup the system and then test something else.

public class When_CreatePerson_is_called
{
    [Fact]
    public void It_should_create_entity()
    {
        // arrange
        var db = new Database();

        // act - testing CreatePerson does what is expected of it
        int id = db.CreatePerson();
        Person p = db.GetPerson(id);

        Assert.NotNull(p);
    }
}

public class When_UpdatePerson_is_called
{
    [Fact]
    public void It_should_update_untity()
    {
        // arrange
        var db = new Database();
        int id = db.CreatePerson(); // Should I use a different way to initialize the system or is it ok to use the system?

        // act
        db.UpdatePerson(id, "John Smith");
        Person p = db.GetPerson(id);

        Assert.Equal("John Smith", p.FullName);
    }
}

2 Answers 2

3

In any one test, this can be either a good or a bad thing. Most likely, it's a good thing that you can write this test at all, and it's a good thing to have a test that runs the real CreatePerson alongside the real UpdatePerson.

In general, the fact that you can use a piece of production code in tests at all is already a good thing. There absolutely should be tests which exercise all of your production code, but whether two pieces of production code should be tested together or separately is much harder to tell.

When you find it difficult to write a test that exercises only one method in the production code, without calling other methods around it, that usually means one of the following:

  1. Because of how the API works, it makes no sense to call that method in isolation, so it's perfectly fine for none of the tests to call it in isolation. For example, almost every test on a dbConnection.executeQuery() method is going to have to call database.makeConnection(). That's just the way databases work.

  2. Your methods are overly coupled to each other, and there's an opportunity to refactor things in a way that would make both the tests and the production code easier to write.

For the specific example you've given, #1 seems far more likely to me. It just doesn't make any sense to update a person that doesn't even exist yet, so in production code nobody's ever going to call UpdatePerson without first calling CreatePerson (or else they get an error...which you should have another test for).

One useful litmus test to help decide is to consider what these two different tests are saying about your public API. If you write a test that calls UpdatePerson on a mock prepopulated database, you're saying that UpdatePerson should always assume that particular database structure, even if it was created by some other API. If you write a test that calls UpdatePerson after calling CreatePerson, you're saying that UpdatePerson should always return whatever was passed into CreatePerson, no matter how it was stored. Which of those sounds more correct for your project?

3
  • yeah its not a create example.
    – andygjp
    Commented May 22, 2016 at 18:29
  • (Ignore the previous comment. Pressed return by mistake.) @Ixrec yeah its not a great example. In the real system I create a customer and then call a stored proc to create an order - the stored proc does various things to initialize an order. I have a test to check its worked. I want to test a separate stored proc that deletes an order, but I want to setup the system using the previous stored proc. I was just concerned if I end up breaking the "create order" stored proc as I then have two failing tests. Should I worry about that?
    – andygjp
    Commented May 22, 2016 at 18:38
  • In a perfect world, the number of failing tests equals the number of bugs. In practice that's only achievable if you know in advance what bugs you'll have, so what you should normally worry about is whether there's a possible bug that wouldn't cause any of the tests to fail. My experience is that it's quite likely for the create method to change what it creates in such a way that update/delete/etc commands suddenly fail, and you really want to catch that bug before getting bad data in your database, so I would normally include the real create method in at least one test for the delete method.
    – Ixrec
    Commented May 22, 2016 at 19:25
2

It is perfectly ok to use production code for your tests as long as you don't shortcircuit the test. For instance, don't do this:

var expected = 4;
var actual = Calc.Subtract(Calc.Add(expected, 1));
Assert.AreEqual(expected, actual);

As long as you know the test fails when anything is wrong, I think it is even better to reuse production code for test setups.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.