I'm relatively new to unit testing, and I've discovered that while many sources say that you should write unit tests, few of them give any indication where to put them in your project.
The only suggestions that I've seen are to put them alongside the production code or to build a directory structure that mirrors your production code. The problem I see with the first approach is that it would become difficult to extract those tests when you make a full build of the system; for the second, how would you test functionality that is only visible at the package level?
Is there a decent way to organize unit tests so that you can easily automate the build process and still access everything that needs to be tested?
EDIT: For those wondering about a specific language, I'm mostly working in Java. However, I'd like to find a solution that's relatively language-agnostic so I can apply it regardless of what platform I'm working on.
Regression testing Still, even if that's your only reason for unit testing, I think putting the unit tests in a separate library is the best choice: It gives you a clearer separation of concerns. If you put unit tests in your production library, it will blur the distinction between production code and test code.
For a file module.py , the unit test should normally be called test_module.py , following Pythonic naming conventions. There are several commonly accepted places to put test_module.py : In the same directory as module.py . In ../tests/test_module.py (at the same level as the code directory).
Unit testing is always done in isolation — that is, the class under test needs to be completely isolated from any other classes or any other systems. If you are testing a class and you need some external entity, then you are no longer unit testing.
The second approach is best. Create a parallel source tree for your tests. Set up your package structure the same. You don't say what language you're using, but if it's Java then code in the test source tree will be able to access code in the main source tree just fine. The fact the the packages have some code from one source tree and some from another is irrelevant - the production code and the test code are still in the same package.
You don't indicate the platform and tools you're using and that has impacts on the options. I'm answering from a .NET and Visual Studio perspective:
My team (working on a quite large project) has successfully used the approach of placing code and tests together. For a given (sub)namespace in the solution, there is a "_Test" folder inside that (sub)namespace, ("_" being a hack to get Visual Studio to display it above everything else in that namespace in the solution browser).
I was introducing TDD on the team and felt that minimum friction in going between tests and code was crucial to the success of adopting the practice. Hence, the tests are always "physically near" the code it tests; you don't want to seek back and forwards in a huge solution to jump between code and tests.
Which makes sense when you think about it. Code and test belong together like yin and yang. That also means only 1 assembly needs to rebuilt when modifying types in 1 assembly (we have well over 30 projects in our solution so this enables us to safely get away with a Build Current Project only when evolving a class via TDD, way faster than a full Solution build).
Having code and tests together also solves the issue of being able to test internal classes. However, on the .NET platform you might also use the InternalsVisibleTo Assembly-level attribute to grant access to a separate test assembly if you want to keep things separate.
The only reason for having tests in separate assembly that I can see is to avoid shipping that code. However, that aspect is trivially solved in another way, if you're using build automation. As Visual Studio's project files are XML, we simply have the build server pre-process the project files, using a small XSLT, to strip everying in a */_Test/* folder from compilation in Release builds.
The problem I see with the first approach is that it would become difficult to extract those tests when you make a full build of the system
You could always filter classes based on some naming convention like a special suffix or prefix when packaging (e.g. don't include **/*Test.class
with Java). I don't really like this approach though, I find it messy and fragile.
for the second, how would you test functionality that is only visible at the package level?
Unless I'm missing something, I don't see the issue. You CAN have classes in the same package and have them living in different trees, e.g.:
src/main/java
for application sources
src/main/java/foo/Bar.java
src/test/java
for tests sources
src/test/java/foo/BarTest.java
Both Bar.java
and BarTest.java
are in the same foo
package but in different directories. This is the approach I use.
Is there a decent way to organize unit tests so that you can easily automate the build process and still access everything that needs to be tested?
Well, as hinted, my test sources and application sources live in the same project but in distinct directory trees and this works really well for me.
This is actually the default layout suggested by Maven (see the Introduction to the Standard Directory Layout). Whatever language you use, this might give you some ideas.
I suggest you have a separate project (or projects) for your unit tests.
It is also a good idea to have a folder on your project tree just for the test projects. This way if you need to build your system without the test you should have a build configuration without building the tests although it is a good idea to build the tests and run them as part of your CI (continuous integration) and than only package the production code in an installer or copy it to a specific folder.
Testing functionality that is only visible on package level is possible depending on the technology used - of example .NET have the ability to make internal methods and classes visible by using InternalVisibleTo attribute. You should ask yourself if you need to test that functionality, it is not advisable to test private methods - because they tend to change.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With