There are answers to the question on how test classes that connect to a database, e.g. "Should service test classes connect …" and "Unit testing – Database coupled app".
So, in short let's assume you have a class A that needs to connect to a database. Instead of letting A actually connect, you provide A with an interface that A may use to connect. For testing you implement this interface with some stuff – without connecting of course. If class B instantiates A it has to pass a "real" database connection to A. But that means B opens a database connection. That means to test B you inject the connection into B. But B is instantiated in class C and so forth.
So at which point do I have to say "here I fetch data from a database and I will not write a unit test for this piece of code"?
In other words: Somewhere in the code in some class I must call sqlDB.connect()
or something similar. How do I test this class?
And is it the same with code that has to deal with a GUI or a file system?
I want to do Unit-Test. Any other kind of test is not related to my question. I know that I will only test one class with it (I so agree with you Kilian). Now, some class has to connect to a DB. If I want to test this class and ask "How do I do this" many say: "Use Dependency Injection!" But that only shifts the problem to another class, doesn't it? So I ask, how do I test the class that really, really establishes the connection?
Bonus question: Some answers here boil down to "Use mock objects!" What does that mean? I mock classes that the class-under-test depend upon. Shall I mock the class-under-test now and actually test the mock (which comes close to the idea of using Template Methods, see below)?
Best Answer
The point of a unit test is to test one class (in fact, it should usually test one method).
This means that when you test class
A
, you inject a test database into it - something self-written, or a lightning-fast in-memory database, whatever gets the job done.However, if you test class
B
, which is a client ofA
, then usually you mock the entireA
object with something else, presumably something that does its job in a primitive, pre-programmed way - without using an actualA
object and certainly without using a database (unlessA
passes the entire database connection back to its caller - but that's so horrible I don't want to think about it). Likewise, when you write a unit test for classC
, which is a client ofB
, you would mock something that takes the role ofB
, and forget aboutA
altogether.If you don't do that, it's no longer a unit test, but a system or integration test. Those are very important as well, but a whole different kettle of fish. To begin with, they are usually more effort to set up and run, it isn't practicable to demand to pass them as a precondition to check-ins, etc.