Don't confusing testing in general with unit testing. Just use the right tool for the job. If your unit tests aren't catching a material number of bugs compared the the effort spent, compared to other testing methods, then don't do them. Unit tests have benefits such as quicker execution time, etc. - but that has to be weighed against cost.
That is not always the case, but that happens in most of the large refactorings i've been involved in.
It doesn't invalidate the fact that unit tests increase your confidence in your own code.
As it happens, I am a Rust fanboy with all that entails, so I (like everyone else in such discussions) am clearly biased.
My point was in jest, as the “;-)” (because HN simply discarded a U+1F609) indicated.
Unit tests are also pretty quick to write once you have the mocking setup.
I've worked both on code where writing the tests was more effort than the code, and on code where writing the tests was easy, quick and helpful. The latter makes sense, after all a good test is straightline code, zero ifs, zero loops. But the former?
I think the key is that mocking should be used sparingly, but without hesitation.
http://googletesting.blogspot.co.uk/2015/04/just-say-no-to-m...
The dirty little secret that nobody talks about is the cause of the ghosts: poorly engineered tests.
That's usually a sign that they've been engineered poorly or you have bugs in your code.
System level integration tests need appropriate environmental isolation and solid asynchronous & multithreaded code. Nobody can be bothered to write these properly for tests, hence the flakiness ("ooh let's just insert a sleep here" / "eh, does it really matter which version of postgres we run?").
Unit tests only can proof your software to be buggy. Even for the extremely simple "two, a function that, given no arguments, returns the number 2", your unit test can't verify that to be _always_ true. It may fail to return on Tuesdays (https://bugs.launchpad.net/ubuntu/+source/file/+bug/248619), internally use a web service that doesn't work on leap days (http://www.wired.com/insights/2012/02/leap-day-azure-outage/), other calls may overwrite the 'constant' it returns (http://programmers.stackexchange.com/questions/254799/ever-c...), etc.
That is true, I don't think anyone argues against that point. What unit tests do, is verify that under the code works under specific conditions (as defined in the test's set up). When unit tests fail under those specific conditions, then you know there is a problem.
Another thing I like about unit tests is that it is much easier (and faster) to test different combinations of conditions
Then, writing tests for the sake of code coverage, is like judging take a driving license exam and being judged on the streets you visited or how much gas you used. Tests need to be written with logic verification in mind.
I am deeply sad this article got upvoted. People should have a sense of responsibility when giving visibility to stuff like this.
I've heard the "executable documentation" line but my general impression is that people usually read the production code. They'll only look at the tests when they fail or they need to modify them.
I'm rather fond of this system, personally.
1: https://doc.rust-lang.org/book/testing.html#documentation-te...
Did you actually read it? Because what you just wrote, is almost exactly the same as what the article author wrote.
His point, as I read it, was that unit tests can have purpose when you don't blindly make them for code coverage.
His case for having unit tests was:
> Keep unit tests that test key algorithms for which there is a broad, formal, independent oracle of correctness, and for which there is ascribable business value
But I don't think he would disagree with the case of providing some "executable documentation" as well. A few lines of code that demonstrate how to use a class or library, along with expected results, is definitely valueable. And those are exactly the kind of interfaces you don't expect to change even when refactoring.
> writing your code in a why that makes it easy to test generally also improves the API and design of the entire system You can get the same result applying SOLID principles, without the cost of maintaining extra code. The presence of unit testing doesn't guarantees easy to test code either (and this is the worse case scenenario, bad designed code with a lot of test coverage that is broken in each refactor).
> is it possible that tests get in the way of completing a project in a timely manner? Are you dismissing this as a point? Time is a resource and writing unit tests adds to that cost.
Unit testing needs to:
* Make you faster because there are less bugs in the long run.
and/or
* Prevent money loss caused by bugs compared to the money lost caused by the opportunity cost of writing unit tests instead of new features.
Also when writing unit tests developers are less prone to refactoring when requirements change as it will require to refactor also all the unit test affected.
You can agree or disagree with the points int he article, but it is NOT just "bullshit".
Unit tests verify logic, the compilers only guarantee syntax. Which yes, handles a huge set of issues that in a dynamic language would require 100% test coverage, you still need to check the logic of the code. Thus, unit tests are still a huge benefit.
One reason I love Rust is the build in #[test] feature. Builtin tests from the ground up, awesome.
Saying you're a Rust fan and then saying compilers only guarantee syntax when the entire point of that language is to have a constrained subset in which types guarantee no data races/leaks at compile time doesn't make sense to me.
Rust is the greatest thing since sliced bread, my comment was only about statically typed and compiled languages in general. I think you read more into my comment than I intended.
The only difference is that Rust's semantics is waaayyy more strict than C's.
I'm not saying that testing isn't needed in either place, but a lot of the times "enterprise" practices that leak into scripted environments make code far more complicated and difficult to understand than it needs to be.
Not every statically-typed language is Java. ;)
Though, I will say writing tests against and with a dynamic language tends to be far easier when things are written with modularity in mind.
Maybe you haven't seen it. But keep in mind that consultants get called in when something has gone wrong. They tend not to see clean codebases by teams that are working well.
It is not a guarantee of anything beyond that. However, having something close to automated deployment means that you should have very close to 100% coverage if only to ensure the above two things.
One thing I've rallied against at several points, more so in scripted environments is DI/IoC, it's often not needed, and there are often simpler solutions than what is generally used. The benefits are being able to have multiple targets for an interface, and being able to more cleanly unit test some systems in a strongly typed compiled language.
All of that said, I don't always go for thorough testing, but I try to write code in such a way that it's more modular, and would be easier to test, should the need arise.
The benefit for DI/IOC for me is mainly not having to worry about how to compose the system.
If some new module I'm writing needs a particular dependency, then I just ask for that in my constructor.
I neither need to know nor care how to set it up or initialise it. That's taken care of by the container - either automatically (convention based registration) or by the maintainer of FooService.
This makes it dead easy to create smaller integration/test harnesses: run the normal container build step, and then resolve an instance of my class, out it pops with all the dependencies handled.
Well... they should be. The number of Tests I've seen that are functionally useless is far too high.
Because what you test is much more important. I know I'm not imparting new wisdom here but if your test can't survive a refactor it's probably a) far too fragile b) poorly written and c) testing the wrong thing.
I actually would not be surprised if a large percentage of Unit Tests are useless, other than coverage stats, but I agree with you that this article is very full of hyperbole to the point of ruining any point it might have had.
That's not really what conflict of interest means, but it's certainly possible that his being in that position gives him a different set of priorities than, say, a project manager, and he's working backwards to come up with an argument that justifies his opinion.
Nope. They may be evidence, but they aren't proof. Proof comes from formal systems like type systems.
Doubt so, he works for a software testing consultancy. They've been around since 1994 apparently. http://rbcs-us.com/
The article is very reasonable, logical and a good counterpoint to the countless TDD anecdotes which obsessively focus on unit-tests to the detriment of any other types of testing or design practices.
But then the separation of concepts is driven by the testability, not the problem per se. It means that there's possibly a lot of complexity just for supporting testing.
* a little, if it passes a decent unit and/or integration test suite;
* a fair bit more, if it survives a round with humans who didn't write it but did set out to break it;
* quite a bit more, once it's been in production for a while without complaints tracing back to it;
* gradually approaching, but never reaching, perfect trust the longer it survives exposure to the world.
A lot of bugs will make it past step 1--even through tests with 100% code coverage. Hopefully no one takes them as anything near proof of correctness.
The drawback of this, is that the test suit grow fast, and need to me groomed pretty often, but it's a fair price to pay and in the end it's faster for me, and produce far less bugs.
IMHO, this is a failing of the type system. If you have functional purity, you don't have a need for unit tests, as they are blended into the code you write. Functional purity gives you the power to formally verify the correctness of your program.
Unit tests are not albotrosses around the neck of your code, they are proof that the work that you just did is correct and you can move on. After that they become proof that any refactor of your code was correct, or if the test fails and doesn't make sense, that the expectations of your test were incorrect. When you go to connect things up after that, and they don't work, you can look at the tests to verify that at least the units of code are working properly.
I am no TDD fan, but I do believe that writing your code in a why that makes it easy to test generally also improves the API and design of the entire system. If it's unit testable, then it has decent separation of concerns, if not, then there may be something wrong (and yes this applies to all situations). I use this methodology for client/server interactions as well where I can run the client code in one thread and the server in another, with no sockets, to simulate their functioning together (thus abstracting out an entire area of potential fault that can be tested in isolation from network issues).
The article/paper raises good points about making sure that the tests are not just being written for the sake of code-coverage, but to say they are useless is just sloppy. Utilize the testing pyramid [1], if you adhere properly to that, everything about your system will be better.
I have a serious question, given that this was written by a consultant, is it possible that tests get in the way of completing a project in a timely manner, thus causing a conflict of interest in terms of testing?
[1] - http://martinfowler.com/bliki/TestPyramid.html