Pedro Magueija
Pedro Magueija

Reputation: 151

Best practices in unit-test writing

I have a "best practices" question. I'm writing a test for a certain method, but there are multiple entry values. Should I write one test for each entry value or should I change the entryValues variable value, and call the .assert() method (doing it for all range of possible values)?

Thank you for your help. Best regards,

Pedro Magueija

edited: I'm using .NET. Visual Studio 2010 with VB.

Upvotes: 3

Views: 1350

Answers (6)

snakehiss
snakehiss

Reputation: 8774

Should I write one test for each entry value or should I change the entryValues variable value, and call the .assert() method (doing it for all range of possible values)?

If you have one code path typically you do not test all possible inputs. What you usually want to test are "interesting" inputs that make good exemplars of the data you will get.

For example if I have a function

define add_one(num) {
  return num+1;
}

I can't write a test for all possible values so I may use MAX_NEGATIVE_INT, -1, 0, 1, MAX_POSITIVE_INT as my test set because they are a good representatives of interesting values I might get.

You should have at least one input for every code path. If you have a function where every value corresponds to a unique code path then I would consider writing a tests for the complete range of possible values. And example of this would be a command parser.

define execute(directive) {
  if (directive == 'quit') { exit; }
  elsif (directive == 'help') { print help; }
  elsif (directive == 'connect') { intialize_connection(); }
  else { warn("unknown directive"); }
}

For the purpose of clarity I used elifs rather than a dispatch table. I think this make it's clear that each unique value that comes in has a different behavior and therefore you would need to test every possible value.

Upvotes: 1

Matthew Farwell
Matthew Farwell

Reputation: 61705

  1. Smaller tests are easier to read.
  2. The name is part of the documentation of the test.
  3. Separate methods give a more precise indication of what has failed.

So if you have a single method like:

void testAll() {
  // setup1
  assert()
  // setup2
  assert()
  // setup3
  assert()
}

In my experience this gets very big very quickly, and so becomes hard to read and understand, so I would do:

void testDivideByZero() {
  // setup
  assert()
}

void testUnderflow() {
  // setup
  assert()
}


void testOverflow() {
  // setup
  assert()
}

Upvotes: 1

Kev Hunter
Kev Hunter

Reputation: 2625

you have two options really, you don't mention which test framework or language you are using so one may not be applicable.

1) if your test framework supports it use a RowTest, MBUnit and Nunit support this if you're using .NET this would allow you to put multiple attributes on your method and each line would be executed as a separate test

2) If not write a test per condition and ensure you give it a meaningful name so that if (when) the test fails you can find the problem easily and it means something to you.

EDIT Its called TestCase in Nunit Nunit TestCase Explination

Upvotes: 0

zoul
zoul

Reputation: 104065

Are you talking about this difference?

- (void) testSomething
{
    [foo callBarWithValue:x];
    assert…
}

- (void) testSomething2
{
    [foo callBarWithValue:y];
    assert…
}

vs.

- (void) testSomething
{
    [foo callBarWithValue:x];
    assert…
    [foo callBarWithValue:y];
    assert…
}

The first version is better in that when a test fails, you’ll have better idea what does not work. The second version is obviously more convenient. Sometimes I even stuff the test values into a collection to save work. I usually choose the first approach when I might want to debug just that single case separately. And of course, I only choose the latter when the test values really belong together and form a coherent unit.

Upvotes: 0

Winston Ewert
Winston Ewert

Reputation: 45039

If one is having to write many tests which vary only in initial input and final output one should use a data driven test. This allows you to define the test once along with a mapping between input and output. The unit testing framework will then interpret it as being one test per case. How to actually do this depends on which framework you are using.

Upvotes: 5

Darin Dimitrov
Darin Dimitrov

Reputation: 1038780

It's better to have separate unit tests for each input/output sets covering the full spectrum of possible values for the method you are trying to test (or at least for those input/output sets that you want to unit test).

Upvotes: 2

Related Questions