2

I've written this set of convenience functions which give nicer names to certain trivial one-line computations. The thing is, I don't feel I can write a test for any of them; anything I write is just "check that f() returns the same thing as running the body of f" - which seems contrived.

What do I do in these situations? Should I just hold my nose and write that? Skip unit tests for these? Something else?

5
  • Rely on integration tests (or visual inspection) for "plumbing" code. Commented Aug 26, 2019 at 0:20
  • 1
    If it's truly a trivial one liner, is your convenience function actually making the code easier to read and maintain? It may help to have an example, but one reason why you may be struggling to write unit tests is that the unit design isn't good.
    – Thomas Owens
    Commented Aug 26, 2019 at 0:20
  • @ThomasOwens occasionally encapsulating one-liners is a matter of giving a bizarre operation a name; that absolutely is for readability. Commented Aug 26, 2019 at 5:53
  • @ThomasOwens: These functions are only about making the code easier to read and maintain.
    – einpoklum
    Commented Aug 26, 2019 at 7:21
  • if these functions are part of public Api / directly used by library consumers then it's fine to test them, even trivial test is useful as a reminder of possible breaking change. However if they are internal to the library then maybe not, tautological tests of internal implementation trivia are not very valuable.
    – KolA
    Commented Aug 26, 2019 at 12:21

2 Answers 2

5

It depends...

There is no rule that everything must be tested with unit tests, or even at all. There is however a lot of evidence that unit tests catch +75% (clarification below) of all errors.


My personal experience is that unit tests will catch +75% of errors before they get to any QA team, based on a relatively mature monolith and internal statistics. Unfortunately I cannot share them, aside from anecdotally.

However, numerous studies have been conducted in the area that are in the public domain. Literature has a general range from nil effect through to the region around 50%.


The issue here is understanding the kind of risks and how risky those are - then choosing to mitigate them or not.

Unit tests are one form of mitigation, there are other ways.

First Question: Is the scope of these one liners tightly controlled?

If the function wrapped one liner is a private member of a class we can argue that it is an implementation detail in the same way that an if statement is an implementation detail. Following this reasoning then we need only check that the class as a whole is well tested.

If the function wrapped one liner is more accessible by code that is written elsewhere/later such as protected scope and inheritance, or in another module etc... it becomes much harder to argue that its an implementation detail.

  • When the new code is being tested, you do not want them to jump into your function to make a correction. This will likely break all of the other usages.
  • Alternately they will compensate for the error locally which will make fixing your function even harder.

This leads to a very fragile code base. An absolute nightmare to work with. Providing even trivial unit tests will help keep things orderly.

Second Question: How risky would an undetected bug be?

If this were in your developer build scripts then the scope is the devs, who each have detailed knowledge, can immediately fix it, and an error is easily detected. If it does break the developer is still likely to persist, and won't leave.

In this case you can argue that the benefits provided by a unit test are already being covered off each time a dev rebuilds. And there are no long lasting negatives, perhaps a little time lost to developers fixing the system (which would already be paid if it broke in a tested world).

If this is an installer/installed program on a users computer. The scope is your client base, who know nothing (in general), cannot fix it, and may not be able to detect where the error is occurring (if at all). If it were to break, the customer is likely to either never again use your software, or spend lots of time with support (which is expensive).

In this case not catching +75% of the bugs translates into 2-3 times more support costs and reputational damage making fewer customers later.

Third Question: How can you be sure that X will still be X later?

Extracting out a one liner into a better named X(), you are doing well in cleaning it up. But what happens later in 6 months? You notice that there is a possible null exception, an overflow, maybe the implementation isn't as efficient as it could be. How will you know that you haven't changed the critical behaviour?

In short you won't. At the moment it is trivial. But later on that function can change or grow. If you don't take the time to record (as a test) what the important behaviour of the function is, then later when you change it (and make a mistake) you may not know about it, till it is too late.

7
  • Sources for 75%? Commented Aug 26, 2019 at 5:54
  • could you elaborate on "a lot of evidence that unit tests catch +75% of all errors."
    – KolA
    Commented Aug 26, 2019 at 12:20
  • Unit tests will never catch a bugs, because same person who wrote a bug will write a unit tests which pass that bug through. We write unite tests for self confidence (or prove for others) that our code works as expected, and as benefit carefully(read correctly) written unit tests provide quick feedback and safe net durinig refactoring.
    – Fabio
    Commented Aug 27, 2019 at 4:08
  • @Fabio, perhaps you need to work on your testing skills. Unit tests written with code are design documents and true they will never catch bugs, but they are not meant too, they are meant to stop bugs from being written by guiding the developer to reflect first. This still reduces overall defects. Conversely Unit tests written afterward are actual tests because you are trying to break your code intentionally. You are not designing but critiquing. Failures in your expectation cause you to improve the code. Again reducing overall defects.
    – Kain0_0
    Commented Aug 27, 2019 at 4:33
  • @fabio Fair enough. Catch in my first claim is directly correlated to the overall defect rate of the code base. ie. they catch bugs, because fewer bugs are being introduced into the code base. My second usage of the word catch is inline with your usage, ie. to detect a bug present but not tested for. In this sense no unit test written as an aide to design will ever "catch" a bug (a failed test). Though it will reduce the number of bugs overall and hence have caught many bugs.
    – Kain0_0
    Commented Aug 27, 2019 at 4:52
4

Doesn't matter if it's a one liner. What matters is if it's a business rule.

Boring structural glue code that connects things together isn't worth a unit test.

A business rule as simple as rejecting negatives is worth unit testing even if it's a one liner.

3
  • It's a FOSS library of low-level code... in a sense, it's all glue :-)
    – einpoklum
    Commented Aug 26, 2019 at 7:22
  • @einpoklum: I'd suggest that the glue is the business logic then and thus worthy of testing.
    – Flater
    Commented Aug 27, 2019 at 12:29
  • If all you do is plug third-party software into third-party software, contributing no thinking of your own then I don't see what's unit testable. If you so much as decide that say names should start with capital letters you have something unit testable and need to rearchitect to make it testable Commented Sep 12, 2019 at 16:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.