Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I need to play devils advocate on this question a bit because I cannot defend it well because of lack of experience. Here is the deal, I get conceptually the differences between unit testing and integration testing. When specifically focusing in on persistence methods and the repository, a unit test would use a mock possibly via a framework like Moq to assert that say an order searched for was returned as expected.

Let's say I have built the following unit test:

[TestMethod]
public void GetOrderByIDTest()
{
   //Uses Moq for dependency for getting order to make sure 
   //ID I set up in 'Arrange' is same one returned to test in 'Assertion'
}

So if I set up OrderIdExpected = 5 and my mock object returns 5 as the ID my test will pass. I get it. I unit tested the code to make sure what my code preforms returns the expected object and ID and not something else.

The argument I will get is this:

"Why not just skip the unit tests and do integration tests? It's testing the database stored procedure and your code together that's important. It seems like too much extra work to have unit tests and integration tests when ultimately I want to know if the database calls and the code work. I know the tests take longer, but they have to be run and tested regardless so it seems pointless to me to have both. Just test against what matters."

I could defend it with a text book definition like: "Well that's an integration test and we need to test the code separately as a unit test and, yada, yada, yada..." This is a case where a purist explanation of practices vs. reality is loosing out. I run into this sometimes and if I can't defend the reasoning behind unit testing code that ultimately relies on external dependencies, than I can't make a case for it.

Any help on this question is greatly appreciated, thanks!

share|improve this question
2  
i say send it straight to user testing...they are going to change the requirements anyhow... –  nathan hayfield Jan 30 '13 at 23:56
    
+1 for the sarcasm to keep things light from time to time –  atconway Jan 31 '13 at 15:56

4 Answers 4

Unit tests and integration tests have different purposes.

Unit tests verify the functionality of your code... that you get what you expect back from the method when you call it. Integration tests test how the code behaves when combined together as a system. You wouldn't expect unit tests to evaluate system behavior, nor would you expect integration tests to verify specific outputs of a particular method.

Unit tests, when done correctly, are easier to set up than integration tests. If you rely solely on integration tests, your testing is going to:

  1. Be more difficult to write, overall,
  2. Be more brittle, due to all of the required dependencies, and
  3. Offer less code coverage.

Bottom line: Use integration testing to verify that the connections between objects are working properly, but lean on unit testing first to verify functional requirements.


All that said, you may not need unit testing for certain repository methods. Unit testing should not be done on trivial methods; if all you're doing is passing through a request for an object to ORM generated code and returning a result, you don't need to unit test that, in most cases; an integration test is adequate.

share|improve this answer
    
Yes thank you for the quick response I appreciate it. My only critique of the response is it falls into the concern of my last paragraph. My opposition will still just hear abstract explanations and definitions and not some deeper reasoning. For example, could you provide reasoning applied to my use case of testing the stored procedure/DB in relation to my code and why unit tests are still valuable in reference to this particular use case? –  atconway Jan 30 '13 at 20:32
1  
If the SP is just returning a result from the database, an integration test may be adequate. If it has non-trivial logic in it, unit tests are indicated. See also stackoverflow.com/questions/1126614/… and msdn.microsoft.com/en-us/library/aa833169(v=vs.100).aspx (SQL Server specific). –  Robert Harvey Jan 30 '13 at 20:35

Unit tests provide a level of modularity that integration tests (by design) cannot. When a system is refactored or recomposed, (and this will happen) unit tests can often be reused, whereas integration tests must often be re-written. Integration tests that try to do the work of something that should be in a unit test are often doing too much, which makes them hard to maintain.

Additionally, including unit testing has the following benefits:

  1. Unit tests allow you to quickly decompose a failing integration test (possibly due to a regression bug) and identify the cause. Moreover, this will communicate the problem to the entire team more quickly than diagrams or other documentation.
  2. Unit tests can serve as examples and documentation (a type of documentation that actually compiles) along with your code. Unlike other documentation you'll know instantly when it's out of date.
  3. Unit tests can serve as baseline performance indicators when trying to decompose larger performance issues, whereas integration tests tend to require lots of instrumentation to find the problem.

It is possible to split your work (and enforce a DRY approach) while using both Unit and Integration tests. Simply rely on unit tests for small units of functionality, and don't repeat any logic that is already in a unit test in an integration test. This will often lead to less work (and therefore less re-work).

share|improve this answer

There are 3 separate things that need testing: the stored procedure, the code that calls the stored procedure (i.e. your repository class), and the consumer. The repository's job is to generate a query and convert the returned data set into a domain object. There's enough code to support unit testing that separate from the actual execution of the query and the creation of the data set.

So (this is a very very simplified example):

interface IOrderRepository
{
    Order GetOrderByID(Guid id);
}

class OrderRepository : IOrderRepository
{
    private readonly ISqlExecutor sqlExecutor;
    public OrderRepository(ISqlExecutor sqlExecutor)
    {
        this.sqlExecutor = sqlExecutor;
    }

    public Order GetOrderByID(Guid id)
    {
        var sql = "SELECT blah, blah FROM Order WHERE OrderId = @p0";
        var dataset = this.sqlExecutor.Execute(sql, p0 = id);
        var result = this.orderFromDataset(dataset);
        return result;
    }
}

Then when testing OrderRepository, pass in a mocked ISqlExecutor and check that the object under test passes in the correct SQL (that's its job) and returns a proper Order object given some result dataset (also mocked). Likely the only way to test the concrete SqlExecutor class is with integration tests, fair enough, but that's a thin wrapper class and will rarely ever change, so big deal.

You still have to unit test your stored procedures too.

share|improve this answer

I am on the pragmatists' side. Don't test your code twice.

We only write integration tests for our repositories. These tests are only dependent on a simple test setup that run against an in-memory database. I think they provide everything a unit test does, and more.

  1. They can substitute for unit tests when doing TDD. While there is some more test code boilerplate to write before you can start with the real code, it works very well with the red/green/refactor approach once everything is in place.
  2. They test the real code of the repository - the code contained in SQL strings or ORM commands. It is more important to verify that the query is correct than it is to verify that you actually sent some string to a StatementExecutor.
  3. They are excellent as regression tests. If they fail, it's always due to a real problem, such as a change in the schema that has not been accounted for.
  4. They are indispensible when changing the database schema. You can be confident that you have not changed the schema in a way that breaks your application as long as the test pass. (The unit test is useless in this case, because when the stored procedure no longer exists, the unit test will still pass.)
share|improve this answer
    
Very pragmatic indeed. I have experienced the case that the in-memory database actually behaves different (not in terms of performance) to my real database, because of slightly different ORM. Take care of that in your integration tests. –  Marcel Jan 30 '13 at 22:43
1  
@Marcel, I've run into that to. I solved it by sometimes running all my tests against a real database. –  Winston Ewert Jan 31 '13 at 0:41

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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