Asserts are useful for telling you about the internal state of the program. For example, that your data structures have a valid state, e.g., that a Time
data structure won't hold the value of 25:61:61
. The conditions checked by asserts are:
Preconditions, which assure that the caller keeps its contract,
Postconditions, which assure that the callee keeps its contract, and
Invariants, which assure that the data structure always holds some property after the function returns. An invariant is a condition that is a precondition and a postcondition.
Unit tests are useful for telling you about the external behavior of the module. Your Stack
may have a consistent state after the push()
method is called, but if the size of the stack doesn't increase by three after it is called three times, then that is an error. (For example, the trivial case where the incorrect push()
implementation only checks the asserts and exits.)
Strictly speaking, the major difference between asserts and unit tests is that unit tests have test data (values to get the program to run), while asserts do not. That is, you can execute your unit tests automatically, while you cannot say the same for assertions. For the sake of this discussion I've assumed that you are talking about executing the program in the context of higher-order function tests (which execute the whole program, and do not drive modules like unit tests). If you are not talking about automated function tests as the means to "see real inputs", then clearly the value lies in automation, and thus the unit tests would win. If you are talking about this in the context of (automated) function tests, then see below.
There can be some overlap in what is being tested. For example, a Stack
's postcondition may actually assert that the stack size increases by one. But there are limits to what can be performed in that assert: Should it also check that the top element is what was just added?
For both, the goal is to increase quality. For unit testing, the goal is to find bugs. For assertions, the goal is to make debugging easier by observing invalid program states as soon as they occur.
Note that neither technique verifies correctness. In fact, if you conduct unit testing with the goal to verify the program is correct, you will likely come up with uninteresting test that you know will work. It's a psychological effect: you'll do whatever it is to meet your goal. If your goal is to find bugs, your activities will reflect that.
Both are important, and have their own purposes.
[As a final note about assertions: To get the most value, you need to use them at all critical points in your program, and not a few key functions. Otherwise, the original source of the problem might have been masked and hard to detect without hours of debugging.]
You should definitely take the same if not better care of your unit tests than your production code in terms of quality and readability. The unit tests are often the first thing you look at when trying to grasp what some piece of code does, and the reader should quickly understand what's at stake when looking at the test. Unit tests also tend to change a lot and will break a lot if their design is not robust, which kind of nullifies the benefits of having tests.
Violation of the Law of Demeter is definitely a problem in your unit tests for that reason as well as 2 others that come off my mind :
If your tests break the Law of Demeter in their Arrange or Act sections, it's probably a sign that your production code also does, since your unit tests are just another consumer of your code and will probably call and operate the class under test in the same way that any other production code would do.
If your tests break the Law of Demeter in their Assert sections (ie you verify the value of something that is deeply nested in the dependencies graph of the object under test), it might be that those are really integration tests rather than unit tests. In other words, if in TestA you assert that A.B.C.D equals something, it might be that you're actually trying to test D and A rather than just A.
By the way, when you say
I break very often the Law of Demeter, for faster writing and not
using so many variables.
you should be aware that writing
var grab = myDependency.Grab;
var something = grab.Something;
var very = something.Very;
very.Deep();
is actually no better Demeter wise than
myDependency.Grab.Something.Very.Deep();
if that's what you meant.
Best Answer
She is not aware of the benefits of unit testing and that's what you need to change:
You will have to prove her it will improve her work not just yours. That will be difficult, she will probably try to focus on every negative aspect she could find if she is afraid of change.
You can try to discuss with her about all the benefits and listen to all her counter arguments. Wait until she finish to talk before starting to talk yourself.
To prepare yourself, you should look on P.SE or Google for all things management or developers are worried about unit testing and compile the answers you will use during your discussions with your colleague.
Just listening to her and provide proof it will improve her work will help you a lot. You prove you are concerned by her opinion, and you provide her with all data she needs to analyze the situation and eventually change her mind.