2

Which of these is better:

function it_should_return_number_of_string_provided()
{
    $this->add(1)->shouldReturn(1);
    $this->add(1)->shouldNotReturn(2);
}

function it_should_return_number_of_string_provided()
{
    $this->add(1)->shouldReturn(1);
}

I.e. should I test both positive and negative results?

Ben Smith
  • 19,589
  • 6
  • 65
  • 93
Marty Wallace
  • 34,046
  • 53
  • 137
  • 200

3 Answers3

1

When it comes to testing, you should test edge cases, a failed case, and a success case.

For example, lets say I was testing a function that returns true for values 1 - 10, and false otherwise. I would probably run the following tests just to make sure I covered all my bases.

OneToTenOrBust(1)    == true
OneToTenOrBust(5)    == true
OneToTenOrBust(10)   == true
OneToTenOrBust(0)    == false
OneToTenOrBust(11)   == false
OneToTenOrBust(-100) == false
OneToTenOrBust(100)  == false

Testing 0,1 was testing my lower bounds edge case. 10,11 was testing my upper bounds edge case. 5 was just a number in range that is true. -100 tested negative numbers. 100 tests for a positive number out of range.

For a dynamically typed language like PHP you also want to check that if your function only can handle ints, that your function can reject 'wrong types' too.

afuzzyllama
  • 6,538
  • 5
  • 47
  • 64
1

Each test should only assert one expectation. So you could instead write:

function When_add_one_number_should_return_one()
{
    $this->add(1)->shouldReturn(1);
}

function When_add_two_numbers_should_not_return_two()
{
    $this->add(1);
    $this->add(1)->shouldNotReturn(2);
}

The test function name is now more expressive i.e. you can deduce what exactly is being tested from the function name.

Also note that the second method now only asserts that the result "shouldNotReturn(2)". There is no need to assert "shouldReturn(1)" on the previous line, as this expectation has already been asserted in the previous test.

Ben Smith
  • 19,589
  • 6
  • 65
  • 93
  • that is going to result in a large number of tests isnt it? a new name for every set of parameters to the same test? Im sure nunit and the likes allow some annotations to create test cases for each test – Marty Wallace Oct 18 '13 at 22:46
  • If you look at Nunit's "Values" attribute, you can specify a range of values. So in the test "when_add_one_number_should_return_one" you'd refactor it to "when_add_value_should_return_value" and you'd use the range attribute to set the values. Obviously my answer caterered for your question, but I agree that using a test framework to specify a range of values is good. As for having a lot of tests, it's not a bad thing if each test is clear as to what exactly it's testing. – Ben Smith Oct 19 '13 at 10:43
  • @MartyWallace did this answer help you in the end? – Ben Smith Mar 14 '14 at 23:28
0

Your test should work for different numbers so you can test it in this way.

function it_should_return_number_of_string_provided()
{
    $randomValue = rand(1, 1000);
    $this->add($randomValue)->shouldReturn($randomValue);
}
Farid Movsumov
  • 12,350
  • 8
  • 71
  • 97