考虑以下伪代码。它旨在确定成绩是否为及格分数。
class Student:
int grade
boolean IsStudentPassing():
return grade >= MIN_PASSING_GRADE
...
// In another file
constant int MIN_PASSING_GRADE = 70
如果我们为IsStudentPassing
编写单元测试,我们可以使用常量值:
ensure that IsStudentPassing is false when grade is MIN_PASSING_GRADE - 1
ensure that IsStudentPassing is true when grade is MIN_PASSING_GRADE
或者,我们可以亲自挑选价值观:
ensure that IsStudentPassing is false when grade is 69
ensure that IsStudentPassing is true when grade is 70
对于第二种方法,如果MIN_PASSING_GRADE
发生变化,则必须重新编写测试。第一种方法更灵活,但依赖于MIN_PASSING_GRADE
具有正确的值。
我不完全确定选择哪种方法,并根据具体情况进行一般选择。一方面,确保MIN_PASSING_GRADE
是理智的,应该通过不同的测试来处理。另一方面,我担心所谓的“单元”测试会触及代码库中的其他许多地方。
这是一个人为的例子,但类似的情况经常出现在真实的程序中。解决这些问题的最佳方法是什么?
答案 0 :(得分:1)
根据您的喜好,您可以使用自己设计的方式注入“常量”值,这样您的单元测试就会与事实上构成通过等级的变幻莫测。这样做有多容易因编程语言而异。请将此代码视为一种易于使用的语言:
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's 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);
}
}
现在,这是Perl,它使猴子修补非常简单(上面的“重要部分”代替了运行时Student::min_passing_grade
的实现)。您还可以将questino中的值设置为默认为常量的属性,或者甚至提供常量文件的特殊版本以供单元测试使用。
如果没有真正强大的表现要求,我会优先选择以上,而不是让价值成为真正的常数。只有当我找不到从单元测试中注入我想要的值的方法时,才能找到常用的常量。在任何情况下,我认为你不应该做的是复制此测试中的常量,这毕竟确保Student
的逻辑是正确的。
答案 1 :(得分:1)
首选项不是使用常量,而是使其成为传递的接口的属性。这就是依赖注入的工作方式(这反过来又有助于TDD)。
然后,您将使用测试(或模拟)框架来生成测试。注:您可能希望在目标值的任一侧测试多个值。您还需要测试数据类型的边界以捕获溢出/下溢错误。
答案 2 :(得分:0)
我过去一直试图操作:单元测试应该检查所有可能的边界条件/压力测试特定功能或整个功能的子集,并且更大的回归套件应该测试整个程序的有效性来自业务需求方。
因此,在您的示例中,第一个测试将在我的单元测试中,第二个测试将在我的回归中。
然而,我是这个行业的新手,并且很想知道我是否走在正确的轨道上。