0

There's already a question about How to write good unit tests.

Based on the answers provided there, the key properties of a good unit test -

  • Short
  • Readable and conveys intent instantly
  • Independent
  • Fast
  • Repeatable
  • Tests a single piece of behaviour
  • Has a good name

Keeping those properties in mind, how would one go about automating checks for ensuring only "good" unit tests are merged back to the main codebase?

I am absolutely of the opinion that automating these checks is the way to go, if it can be reasonably achieved. There are so many things a reviewer needs to watch out for when accepting a merge request - clean code, design, architecture, clean tests etc. so reducing the burden by automating checks that used to be manual is always welcome.

  • 2
    wonder how would one automatically check for SRP or good name – gnat May 25 '17 at 0:08
  • 1
    You could count asserts for SRP. The name, well you could at least ensure it follows a convention (Given/When/Then or some such). – thegreendroid May 25 '17 at 1:36
  • 4
    Testing one thing does not mean Have one assert. It's perfectly valid to have multiple asserts in a single test as long as you test a single behaviour. – Vincent Savard May 25 '17 at 11:20
  • 1
    One solution is to implement hard AI – Weyland Yutani May 25 '17 at 15:13
  • I read that answer and the term SRP does not exist, and "test only one thing" appeared only twice, and not in the checklists from the two books cited. I strongly disagree that SRP is a "key property" of a good unit test. Also agree with Victor that multiple asserts are fine. – user949300 Jul 5 '17 at 6:08
5

Lets sort your properties by ease of automated checking:

  • Fast - Most IDE's already tell you this

  • Short - Your line count tells you this (so long as you don't abuse white space)

  • Repeatable - Rerunning already tells you this

  • Independent - This could be done by listing what files the test requires, and what they require ...

  • Tests one thing (SRP) - Count your asserts. Is there more than one?

  • Readable - Simple, write an AI that writes code and invite it to the code review. Ask what it thinks.

  • Has a good name - Hope the AI is smarter than humans because even we suck at this.

  • 3
    Obligatory xkcd xkcd.com/1425 – RubberDuck May 25 '17 at 0:41
  • 2
    "Simple, write an AI that writes code and invite it to the code review. Ask what it thinks". Haha gold. I agree with your points though. – thegreendroid May 25 '17 at 1:41
  • 5
    I cannot agree with your explanation for SRP. Multiple asserts sometimes have their reason. For example a return value is supposed to be between 0 and 1000 then you can check both limits independently and thus you have checked a single thing using multiple assert statements. Forbidding multiple asserts leads to boilerplate unit tests who do the same thing over and over again and always check not one thing but a fragment of one thing – BlueWizard May 25 '17 at 8:41
  • 1
    @scriptin All sillyness aside, SRP doesn't care if it's a short one liner, a long one liner, or multiple lines. It's one clear idea that would only have one reason to change. But if you can pull it off with one short assert you're likely OK. – candied_orange May 25 '17 at 15:20
  • 4
    @9000 Not a bad idea! Tests should have a cyclomatic complexity of one (i.e. no more than one path through the test). It's a pretty neat way of ensuring tests are simple. – thegreendroid May 25 '17 at 23:29
7

Your characteristics of unit tests are missing some of important features in my opinion:

  1. Reflects and traceable to requirements
  2. Tests all of the requirements for that unit under test
  3. Covers all corner cases
  4. Tests every line of the code & possibly every decision path

The main point of a good test is that it fails when something is wrong and not when nothing is wrong and lets you find out what was wrong so look for:

  1. Comprehensive
  2. Accurate
  3. Complete
  4. Good clear fail messages with what failed & how.
  • unit tests cannot test all of the requirements. 1) Mean time between failure of the system is 480 hours. 2) System is available 99.4% of working hours. – BobDalgleish May 25 '17 at 12:56
  • @BobDalgleish - we are talking about unit tests not system tests - so unit requirements would apply these rarely have things like MTBF or Availability. I will update the answer. – Steve Barnes May 25 '17 at 14:48
  • Big +1 for "it fails when something is wrong". Everything else is gravy. :-) – user949300 Jul 5 '17 at 6:09
4

As already mentioned, a good test fails when the system under test experiences "breaking" changes.

To automatically evaluate new unit tests based on above criteria you could try to implement mutation testing:

  • Determine what parts of the project are covered by the new test.
  • Generate some mutants by applying (one or more) small modifications (switching operators and such) in those parts.
  • Run the new test on each mutant. If the test fails, that's good (the test could be too strict, but that's not so much an issue compared with a test that's too weak). If the test doesn't fail, then you probably need some human review of the modifications​ of the corresponding mutant; it could be an indication that the test is too weak or doesn't cover all cases.

You'll probably get lots of false negatives at first. It will probably improve by careful selection of mutation operations that actually lead to failures. As an example, switching adjacent declarations of local variables is probably rather unlikely to yield significant errors.

  • 1
    This is a great approach, exemplified by QuickCheck and Hypothesis on one hand, and fuzzing tests on the other hand. – 9000 May 25 '17 at 16:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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