Unit testing, Lean Startup, and everything in-between
codewithoutrules.com
codewithoutrules.com
Anyway, the article seems like a brain-storming session from the author, so I am not sure that I need to answer all the points. Those that stick out
1)As other people said already you always write a unit test against a spec. If you have no spec, then unit tests are not really helpful. When you prototype something you don't need unit tests. Most startups also would not need a vast test suite in their early stages
2) The company that had only UI tests forgot to make them resistant against ui changes. I don't know the tool they were using but most GUI tools support the Object/pages pattern. If the UI was changing so much that even that was not enough, then they did not have spec (see point 1)
3) A/B testing is not unit testing because by definition you don't have a spec (if you are still trying to find if A or B are ok)
4) Code review is not unit testing because you will catch only obvious stuff. Code review is more about the structure of the code than its correctness. It far easier to judge correctness by automation than by visual inspection.
Basically I would suggest you to remove the word "unit" from your blog post title.
Unit testing has a very clear definition and you are confusing it with code reviews, A/B tests and other unrelated stuff
google also "the testing pyramid" for a sound model of unit testing. The tax preparation company would do fine to follow this.
The testing pyramid, IIRC, starts with the presumption that the goal of testing is quality. There are other goals for testing, though, and I say in the intro quality is too hand wavy to be useful in decision making.
Here's how I'm doing it, for command line tool that provides local development environment for remote Kubernetes cluster (https://datawire.github.io/telepresence/):
1. Build prototype, test manually.
2. Have coworkers try it out.
3. Fix UX based on feedback, test manually.
4. Once initial UX was nailed down, write end-to-end tests.
Beyond adding features, next I will rewrite the core using test-driven development (TDD), so that the internals are maintainable. and the end-to-end tests will ensure the basic functionality continues to work.
The UI is fairly simple, and at this point I have confidence that it won't change multiple times in a day, so it's worth the effort to stop relying solely on manual testing and write some automated UI tests.
So yes, start writing unit tests when you no longer prototype.
If you have library code that won't get rewritten it should have unit tests, of course, since you want that to be stable.
Waste of time? I'd argue that right amount of unit and other automated tests actually decreases time to market as it allows make changes to the software much quicker and push it to production with more confidence. Yes, at early stages, when it is not clear whether anyone needs the software.
Sure a badly written test suite only slows down development. Tests should be written so they would indicate breakage early and address unstable, complex, but highly used parts of program.
For library code I'd use TDD, though.
UIs are more suited to human testing (though cost pushes towards automated testing once the UI is stable enough), APIs are more suited to automated testing. And if you're doing prototyping or usability testing you might not need either (you might not even need to write code, sometimes).
https://martinfowler.com/bliki/PageObject.html
There are several testing tools that support this pattern.
It isn't clear in your article.
This sounds plausible right up until you realize that 1 out of every 3 production deploys breaks some corner of your web UI, and you're always needing to scramble to fix the deductions table every time you change your basic popup widget. Or until you realize that you need a full week of time from two very skilled testers to make sure your UI actually works.
JavaScript UIs bitrot at incredible speed. Sure, if you're using TypeScript and Angular, you can maybe get away with a bit less testing. But in most cases it's a terrible tradeoff.
There's a huge comfort in knowing that every single time you deploy your application, your basic signup flow and core features still work. You can accomplish this with very high-level tools like Cucumber in most cases. "Stable Functionality" is always desirable, and it allows you to develop faster because you don't have to spend all your time terrified of breaking things and endlessly retesting them by hand.
Or you can keep breaking weird corners of production and getting upset because somebody made a mistake and annoyed an important customer again.
There is no single right answer: it's all about tradeoffs. And in order to make those tradeoffs you need to understand strengths and weaknesses of each form of testing.
In terms of unit tests, the audience stops being the users, and starts being other developers. Good unit tests should do more than just check that a function/method works as expected, but provide a list of examples of how to use a method as well as noting the return types/exceptions/etc for other developers.
Using the author's example that even after writing Selenium tests the application is still buggy. There are several issues in just this one example:
1. The application may be buggy, but did the business know about the bugs?
2. If the business knew about the bugs, did users work around the problems or did they avoid certain features altogether?
3. When the UI changes, yes, your Selenium tests may be expected to break. If a user expects to click "Next" and you changed that label to be ">", the test breaking is a sign you need to communicate something to the user either through change-logs or training.
At the end of the day, tests exercise and lock down behaviour of code. Whether behaviour and functionality is desirable, correct, or worth locking down is not a technical problem. Furthermore, your tests themselves are code, therefore some care must be taken to ensure your tests are valid too.
Sometimes you want stability. Testing for stability is worth doing then. Sometimes you can't have stability, and automated tests are just an expense.
It all depends on situation and goals.
An interesting addendum might be: How to manage expectations when transitioning from the pre-traction to traction stages? How do you decide between adding new features vs. adding new automated tests to a system when things seem to be going well? "Technical debt management" might be another way of phrasing this conundrum.
What's worse, failing fast in spite of your tests, or squandering your traction because your technical debt slowed you down?
One thing that would be interesting to explore is how things can change over time. Something that you thought would be stable may end up not being as stable as you thought. I feel this should factor in somehow.
Quality is a multi-pronged effort. It starts with the architecture, design, coding. As this says, the connection between testing and quality is vague. Testing can give you more confidence the quality is there or it can show you the system under test is of poor quality but it won't change one into the other. If you have something of poor quality, you do a lot of testing, you file a lot of bugs and fix them most likely it's still of poor quality. Testing definitely has a role in building high quality systems but on its own is insufficient.
This discussion reminds me a little of efficient frontier in portfolio management. There is some optimal mix of all your development activities just like there is a mix of different assets in your portfolio. The assets you pick and their mixture affect the probability distribution of the outcomes. Just like in portfolio management part of the problem is that the historic performance of these assets doesn't necessarily indicate future performance.
I find manual point and click testing is often cumbersome and slower particularly if you need to go through a few screens to test your feature/bugfix.
And always unit test at least your core functionality.