Should unit test rely on constants defined by the application?

Consider the following pseudo code. It is intended to determine if a class is a passed class.

class Student: int grade boolean IsStudentPassing(): return grade >= MIN_PASSING_GRADE ... // In another file constant int MIN_PASSING_GRADE = 70 

If we wrote unit test for IsStudentPassing , we could use a constant value:

 ensure that IsStudentPassing is false when grade is MIN_PASSING_GRADE - 1 ensure that IsStudentPassing is true when grade is MIN_PASSING_GRADE 

Or we could manually select the values:

 ensure that IsStudentPassing is false when grade is 69 ensure that IsStudentPassing is true when grade is 70 

For the second approach, our test should be rewritten if MIN_PASSING_GRADE changes. The first approach is more flexible, but relies on MIN_PASSING_GRADE , which has the correct value.

I'm not quite sure which approach prefers, and generally choose in each case. On the one hand, to ensure that MIN_PASSING_GRADE normal, you should take care of another test. On the other hand, I am worried about the supposedly “single” test involving too many other places in the code base.

This is a contrived example, but similar situations are often found in real programs. What is the best approach to solve them?

+6
source share
3 answers

If you wish, you will introduce a “constant” value by one of your own developments, so that your unit test is isolated from the vagaries of what is actually a passing class. How easy it is to do this depends on the programming language. Consider this code for a language that simplifies:

 use MooseX::Declare; class Student { has grade => ( is => 'ro', isa => 'Num', required => 1, ); method min_passing_grade { return MIN_PASSING_GRADE; ) method is_student_passing () { return $self->grade >= $self->min_passing_grade } } class t::Student { use Test::Sweet; use Test::MockObject::Extends; test correctly_determines_student_is_passing () { my $student = $self->_make_student($self->_passing_grade); ok($student->is_student_passing); } method _make_student (Num $grade) { my $student = Test::MockObject::Extends->new( $student->new(grade => $grade) ); # Here the important line: $student->set_always( min_passing_grade => $self->_passing_grade ); return $student; } method _passing_grade () { 40 } test correctly_determines_student_is_failing () { my $student = $self->_make_student($self->_passing_grade - 1); ok(not $student->is_student_passing); } } 

Now this Perl, which makes fixing monkeys pretty simple (the “important line” above replaces the implementation of Student::min_passing_grade at run time). You can also have a value in questino as an attribute that defaults to constants or even provides a special version of the constant file for use by your unit test.

The lack of a really strong performance requirement, I'm going to choose above, preferring the value to be a real constant. Only if I cannot find a way to insert the value that I want from my unit test will I get for the usually defined constants. What I don’t think you should do under almost any circumstance is to duplicate a constant in this test, which ultimately guarantees the correct Student logic.

+1
source

The preference would be not to use a constant at all, but to make it a property of the interface that is being passed. This is how dependency injection works (which in turn helps TDD).

Then you should use the test (or mocking) structure to generate the tests. Notably, you probably want to test more than a few values ​​on each side of the target value. You will also want to check the boundaries of the data type to catch overflow / underload errors.

+1
source

As I always tried to work in the past: unit tests should check all possible boundary conditions / stress tests for a specific function or a subset of all functionality and that a larger set of regression should check the entire program for validity from the side of business requirements.

Therefore, in your example, the first test will be in my unit tests, and the second in my regression.

I am a relative newcomer to the industry, however, and would like to know if I am on the right track.

0
source

Source: https://habr.com/ru/post/925051/


All Articles