I want to test my code written in D. I am using DUB to build the project (but the config is fairly basic so far: just the name and dunit
dependency).
I have seen in many projects that unit tests are placed next to the actual code (e.g. http://wiki.dlang.org/Unittest#Placement).
While this is IMO ok for small modules and simple tests, what if I really wanted to test my code?
In Java (and other JVM languages) the convention is quite the opposite - to keep the tests in separate files (usually mirroring the packaging of units under tests).
Is it possible to have separate files for unit tests in D?
I'd love to have a classic setup:
dub.json
/source/mylib/app.d
/tests/mylib/app_tests.d
with the file app_tests
(as other files unter tests
) integrated with DUB - compiled/run only during --unittests
etc.
You'll put unit tests in the src directory in each file with the code that they're testing. The convention is to create a module named tests in each file to contain the test functions and to annotate the module with cfg(test) .
Unit tests run against specific lines of code. So it makes sense to place them right next to that code. Integration tests run against many lines of code in many files. There is no single place that would make sense, so it's best to have them in a /tests directory.
Avoid Test Interdependence You, therefore, cannot count on the test suite or the class that you're testing to maintain state in between tests. But that won't always make itself obvious to you. If you have two tests, for instance, the test runner may happen to execute them in the same order each time.
I don't know about conventions, but I recently came across such a solution for DUB:
{
"name": "sample",
"description": "sample app",
"configurations": [
{
"name": "application",
"targetType": "executable",
},
{
"name": "unittest",
"targetType": "executable",
"targetPath" : "tests",
"buildOptions": ["unittests"],
"excludedSourceFiles": ["source/app.d"],
"sourcePaths": ["tests/"],
"importPaths": ["tests/"],
"dependencies": {
"dunit": ">=1.0.9"
}
}
]
}
I found the idea in the DUB sources. Now if you run dub
the app will be built, and if you run dub test
the unit tests (placed in tests/
) will be run.
This is not perfect and I still haven't worked everything out, but works for my simple needs.
One of the issues is that the separate unit test modules don't have access to private elements in the sources (they may have access to package and public though).
I am not entirely sure if there aren't some side effects of this configuration that I am not aware of. Maybe someone more experienced will validate this approach.
There's nothing stopping you from having unittest
blocks in one file test code from another module. You can put anything in a unittest
block that you could put in a normal function. However, you won't be able to access any of the private members of the module being tested unless the unittest
blocks are in the module being tested. The normal restrictions of access modifiers apply.
There are some folks in the D community who don't like having their unit tests next to what's being tested and choose to put the tests in separate files, but D's unit testing facilities were designed with the idea that you would put the tests right next to the functions that they're testing. This makes it far more obvious when you forget to unit test a function and makes it easier to modify the code and tests together. It's what D's standard library does, and AFAIK, it's what most D programmers choose to do. IMHO, it's far better for maintenance that way, and if you think that it makes a module too large then either you're probably making your modules too large anyway, or you're being too picky about how large a module is. But obviously, it's subjective, and it's up to you whether you want to put your tests in the same module as what they're testing. You just have to keep in mind that if they're separate, then they can't access any private members of the module being tested.
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