Posts Tagged testing
We normally hear that we should only be writing tests for our code, not someone else’s (external libraries or APIs). For example, if we are writing tests for code that calls out to an API, the test should mock the dependency on the API and only verify that the calls are made as expected and that the results are handled as expected. The test should NOT verify that the API produces the appropriate results for the given the input; that would be testing someone else’s code.
I agree with all of that; for unit tests.
However, I’d still consider writing integration tests against that API, NOT to test someone else’s code, but to document our assumptions about the API.
Why? Because our code relies on those assumptions. That’s a dependency.
What happens if the API implementors decide to make changes that break our assumptions? Without integration tests validating those assumptions, all our unit tests would still pass, but we could end up with either defects or inaccurate results in production (which could go unnoticed for a long time).
Another added benefit from the practice of writing such tests is that, should a new version of the API come out, evaluating risk levels of consuming the new version becomes much simpler: just run the tests against the new version.
Last but not least, say an API offers a large variety of features that could be used; having tests that describe how we use that API makes it much easier for developers to learn the details of how we depend on it. Such understanding, again, helps with both assessing risks when consuming different versions of the API, as well as assessing a potential replacement of the API.
Dependency management is very important!
Did I get your attention with that title? I hope so.
Let me clarify it: most people use code coverage for the wrong reason, making it worthless. I know I did that for a while.
Back when I first learned about writing tests, it didn’t take long until I heard about code coverage, and then the search for the magic code coverage percentage started:
“100% code coverage?”. Nope, that’s impractical
“50%, then?”. Nope, too low.
“92.35?”. Yeah, that’s more like it! Well… not!
Seriously, I’ve seen some crazy numbers as the required code coverage policy out there.
Writing tests for the sake of bringing up code coverage will NOT:
- make the code quality get better
- delivery better value to the business
- make refactoring easier
I have seen tests out there that have no assertions.
Those tests have hundreds of lines of code (usually involving some crazy, unreadable mock setups), and no assertions. Why? Simple: because developers had to satisfy the policy of XX% code coverage! The only thing those tests do is make sure no exceptions get thrown when those lines of code run. It’s pretty much a smoke test.
Such tests do NOT bring value. In many cases, the tests may be exercising lines of code for features that aren’t even used!
Think of new developers joining the project and having to go through all of that code trying to learn things, figuring out how things are done. Even existing developers after a while will have a hard time remembering why certain code is there.
So, when is code coverage worthwhile?
When writing tests for existing code!
Once a conscious decision has been made about what we should write tests for, start by writing a test that does a clean pass through the code (meaning, without it throwing exceptions). We’re likely to uncover dependencies we didn’t even know the code had. This will be a big integration test. I wouldn’t even fret about putting assertions in that test. Why? It’s very likely I don’t even know what the expect outcome of that code is at that moment.
With the first clean pass in place, look at the code coverage number. If we have about 30%, that’s too low, so we need to look into writing more tests that go through different branches of the code. Once we get to a number we feel comfortable with (that could be 70, 80, 90%… it really depends on the risks and costs of breaking changes), then we can start capturing the current outcome of that code, by writing assertions for it, bearing in mind that the outcome may not even be accurate, but it is what the code produces without any changes.
Now we can go ahead and start refactoring the code, making it more readable, without fear of breaking whatever it currently does. As we split it into smaller chunks of code, we identify opportunities to write new unit tests for those smaller pieces of logic.
Eventually, we’ll get to a point where that initially big integration test may either end up not being relevant anymore (and can be removed, replaced by the new unit tests), or, it can be refactored to something that more accurately describes the reason the code exists; the big picture.
Once the team starts using code coverage for the right reasons, then the metrics can be changed over from “Code Coverage” to “Feature Coverage”. Knowing what features are covered by test is a far more valuable practice.
If you choose to get one thing out of this post, may it be this: read Working Effective with Legacy Code, by Michael Feathers. It still one of my all-time favorite books.
Another common question I get from developers who are starting to get into testing (or even from devs who have been doing it for a while): “how do you decide what to write tests for?”.
This question normally applies to brownfield cases (existing codebase). There’s already a lot of code there. Where do we even start? Yes, maybe we write tests for the new code, but what about the existing one?!
Here’s my personal technique for it. When working with an existing codebase, I’ll ask the business:
What is the single most important feature of this product?
Think of the feature that, if broken, will either cause the business to lose money or not make money.
THAT is where we start. Those are our must-have tests.
Once the most important features have been covered by tests, the next question is:
What is the feature or area of the system that when you tell developers they need to make changes to it, they feel like running away?
That’ll usually surface areas where the code is a mess, complex, convoluted. Hence, it needs tests, so developers can feel safe making changes to it, refactoring it. Now, we only move on to this one when the features that came out of the first question above have been covered by tests.
A very common question I hear from developers is “How do I write tests for private methods?”. My immediate answer is “You don’t!”. Technically, if you’re in C# Land, you can instantiate the class and then use Reflection to call the private method. But please don’t!
Say you have some class like this one:
Of course, instead of comments, you’d have the actual code. You get the point.
You then decide to clean things up a bit and extract the “make sure all the ingredients are in” code into a separate, private ValidateIngredients method, like so:
That’s usually the moment when developers ask “how do I test that private method?”. If we have tests for the main method (DoTheMagic, in this example), then ValidateIngredients already get test coverage.
Quite often, when developers feel strong about having separate tests for a private method, there’s a clear indication that the private method should really be a public method on a separate class. Think Single Responsibility Principle.
Following the example above, we create a Validator class and move our validation logic in there:
And then we use that validator in the previously shown class:
You’ve probably noticed that we also introduced an IValidatePotion interface. Think Dependency Inversion Principle. One of the benefits here is being able to isolate tests for the AwesomenessPotion and AswesomenessPotionValidator classes.
I’m often asked about comments in code: when to do it, how to do it, what to put, etc. I’ve recently run into Steve’s post about when to comment your code, left a comment (!) there, and we got to expand our conversation in his podcast/screencast (link at the bottom). I’ve decided to create this post to consolidate the links and info shared during the interview, to make it easy for folks to find the material.
I remembered writing blog posts a couple of times over the years and it’s interesting to see how my opinion on this subject has changed over time.
The first post goes all the way back to 2005, with me asking “can you plesae put some comment on that Regular Expression?”. 15 years later, I still ask my smart friends to get me the RegEx I need, along some comments as to what each piece does!
In 2007, I was big into using Xml Comments, GhostDoct, and Documentor… I’m not anymore, as documented 10 years later with my post “XmlDoc Comments: Auto Generate and Hide the Clutter”. In nutshell, if we’re documenting a public API, yes, by all means let’s put in that documentation, but making it count: commenting the GetCustomers endpoint with “Gets the customers” doesn’t add any value to the effort!
My practice of making comments stick out as a sore thumb posted in 2010 still stands in 2020: I still set up all of my IDEs in that manner and it still produces exactly the outcome as I intended.
When I do want to drop a quick TODO comments in code (watch/listen to the podcast interview when it’s up to know why I might do that), I have templates on my IDEs to automate that: ReSharper in Visual Studio, User Snippet in VS Code, Live Template in RubyMine.
In regards to code that’s commented out, like so:
We should be using a source control system; if we ever want that code back, we have a way to bring it back. So just remove it!
Still using the example above, notice that each if-block is preceeded by a comment. Is it really necessary? How about removing the comment and extracting the expression into a method that tells us the question being asked?
There’s also the “narrator-style” comment:
Narrating every single line of code is very annoying (by the way, I think I wrote the code above many moons ago). If the comments were written initially as a placeholder for the steps that needed to be implemented, let’s make sure to get rid of it when we’re done.
Last but not least, some people say (I’ve said it myself) that comments should document “why” the code was written in such manner. I’d propose a variaton to that: how about documenting the why with some good specs (or tests, if that’s how you prefer)?
Now, I’m not refering to tests that look like this:
Such test doesn’t tell us the “why”; it tells us the “how”. I mean this kind of test (now you’ll see why spec fits better):
Summing it up, this is how I prefer to “comment” code:
- Given-When-Then specs
- Writing code English-first
If I do have a real need to drop an actual comment in code (“why do we have this query in the code that has to potential to perform badly”), I’ll probably drop a quick comment, with a link out to the issue tracker, where I’ll put more context about why the code was left like that, and where a Product Owner can decide when it’s appropriate to address the situation.
Any comments? 🙂
And for audio-only version:
My “Testing in Agile: From an Afterthought to an Integral Part” is becoming a hit: I’ve been receiving great feedback and compliments from attendees and many requests to deliver it as a Lunch and Learn at their companies (drop me a note if you’re in the Houston or surrounding area, and I’ll come to your company, too!). I’m so pleased with the response I’ve been getting that I really feel like working on polishing the presentation further (better title, better description, etc.).
One of the points I bring up on this presentation is my “No GWT, no code!” movement. 🙂
As it turns out, people are responding well to that! At some conferences and user groups, when I mention the movement (which initially just came out as a funny remark), I hear attendees saying out loud “YES!!!”. But now, the coolest thing happened… check this out:
I just got to the Improving Houston office and had an envelope that came in the mail for me. What is it?
Yes, “No GWT, no code.” stickers!!
An attendee to my talk at one of the conferences felt inspired, got these made, and mailed it to me. How awesome is that?!
The realization that you’re inspiring others with your work and attitude brings so much joy, while it also keeps the flame burning, providing energy to keep pushing forward. You should try it, too!
I’m going to be speaking at the AgileShift Conference in April!
I’ll be delivering my current favorite talk, for which I’ve been receiving great feedback from people who have seen it (ranging from software developers, QA, business analysts, product owners, etc.):
Testing in Agile: From Afterthought to an Integral Part
Testing cannot be an afterthought; it has to be an integral part of software development. Is it something that QA teams do? Or is it part of a developer’s duties? Do business analysts play any role in it? What is test automation? Unit test, Integration test, Test-Driven Development, Behavior-Driven Development… what do those mean?! This session addresses all of those questions, as we talk through the importance of tests, the collaboration among team members, the techniques, and practices around different kinds of automated testing.
I hope to see you at the conference! 🙂
When I started to work on some Ruby on Rails projects almost 8 years ago, I knew zero about it. Instead of jumping head-first into learning the language (Ruby) and the framework (Rails), I started by learning how to write unit tests for it. That was the tiniest thing I could do to get my feet wet (passing tests give me that instant gratification we all crave for).
Learning how to write unit tests in whatever language should be relatively easy; if it’s not, I probably would not consider working in such language to begin with!
After learning the basics of writing tests, I can implement simple things in the language however I can, which back then, it meant I was “speaking Ruby with a C# accent”. That’s ok, because once I see my tests passing, I can poke someone who knows a lot more about the language than I do to teach me the better ways to both write the implementation, as well as the test.
More recently, as I started getting my feet wet on ReactJS, one of my first questions was: “how do I write tests for this thing?”.
That gets the ball rolling for me…
When I first started writing unit tests, I followed the common convention in C# for method naming:
Later, I adopted the convention of separating words with underscores:
At some point I figured the approach above makes the name of the method look like the title of an article. I then decided to go with the same approach, but making everything lower case:
In some cases, I may use uppercase if I want to draw attention to something in particular:
I like when the code is calm to look at, and it draws my attention to things as appropriate.
This is a question asked many times: What is the difference between Test-Driven Development (TDD) and Behavior-Driven Development (BDD).
In my mind, I’ve accepted the following explanation:
Doing TDD, I write the code I want to have;
Doing BDD: I describe the behavior I need to have
I use both approches together: I start writing my tests in terms of GWT (Given-When-Then), describing the behavior I need to have, and as I implement those individual steps I write the code I want to have.
This is the simplified explanation that works in my own mind, and it has taken many years for it to take that shape. It may not work to others, but I’m sticking with it for the time being, at least until I find a better way to explain it.
I sense there’ll be more posts coming up expending on this subject. 🙂