On March 18th, I presented “Testing MEAN Apps With Javascript” to the Indy.JS meetup group. The room was packed as we covered the basics of why we do developer testing, and how to test apps that are built with Mongo, Angular, Express, and Node. Most of the code was devoted to showing how to test Mongoose models, Express routes and controllers, and Node functions with Mocha and Sinon. Here is the slide deck (written with reveal.js):
Some supporting comments
Some comments from the slides (in my super-secret speaker deck…):
What is testing?
You already do testing, probably on at least a manual basis.
For the purposes of this talk, testing is automated developer testing. These are tests that you write to verify the code that you write and to move more quickly.
I won’t be talking much about QA-style testing, although you could possibly use the tools that are covered here, especially protractor.
Why Test?
Verify code works as expected
Document expectations and assumptions
Code as documentation of what you expect to receive.
Ensure code continues to work as expected
Protect the functionality that you intend from package updates, teammates, and future you.
Imagine you are working with a team of twenty, how likely would it be that everyone knows how to not break the app?
Increased feedback
Instead of finding out that you broke something a week from now when you deploy to production, find out in one minute locally before anyone else finds out.
Increased confidence in changes
Ever feel scared to push the deploy button or feel like you are probably breaking something? With solid code coverage, you can feel more confident in making even sweeping changes.
Better Design
Potentially controversial.
Writing tests, especially test-first, forces you to think about how to make your code more testable. Typically this means isolating dependencies, making modules do just one thing, focusing on interfaces between modules, etc.
If anything, it will mostly end 100 line functions with ten conditionals.
Development speed
Potentially controversial.
Like touch typing, it is slower at first, and then you get increased speed and accuracy.
I personally think this is true, especially when you take maintenance into account.
Help Debugging
If you have code that is doing something funny, you can write a test that exposes the behavior to ensure that you can reproduce it, and that when it passes that you have fixed the issue. Also, prevents regressions.
You can also test things that are hard to set up like workers.
Toward Continuous Deployment
If you are to continuously deploy code, having solid tests is critical.
Automate manual testing process in order to be able to deploy automatically with confidence.
Know when to stop
When the tests that are reasonable all pass consistently, you are done. Writing tests helps ensure we don’t gold-plate code and just have it do what it needs to do today.
Why Not Test? (Challenges in Testing)
Must be valuable
It must be something that is valued by your team and done well.
The ROI of tests needs to be high, or it is not worth it.
Think to yourself, is this test valuable enough to run 1000 times? If it breaks, what does that mean?
Learning curve
Part of the cultural issue is that people are resistant to change, and especially when there is a learning curve with a change.
Touch typing as example
It might take me a few months of going more slowly to be able to produce higher quality code more quickly.
Culture
Many challenges in testing come down to culture. If you are the only person on your team writing tests, there will be issues. If you are the only person not writing tests, there will be issues.
Intermittent Tests
One of the hardest problems to solve.
Hard because of ownership. Who takes ownership for a test that seemed to pass but now fails because another test leaks state?
Need high reliability. Fortunately, easier to do with JS test frameworks than other frameworks that I have used.
Test fragility
It is possible and even sometimes easy to write tests that fail when the production code is changed in small ways. Writing robust tests is a skill.
We’re not sure what we are building…
I would say to really try to figure out what you are currently trying to build before trying to build it. If it not clear, keep asking questions.
At some point between when you deliver the code and now, you will need to figure out what you think it should do, so when you figure that out, you know what your tests are. You can always change, add, or remove tests.
Spike and stabilize - write working code first and then the tests later if the spike is viable or useful (or throw away the code after you have written it and try again with tests first.)
Cannot prove a negative
Your code will never be bug-free. But tests may give you a reasonable level of confidence.