unit-testing - 单元测试是否应该依赖于应用程序定义的常量?

标签 unit-testing testing language-agnostic constants

考虑以下伪代码。它旨在确定成绩是否为及格成绩。

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 正常。另一方面,我担心所谓的“单元”测试会触及代码库中的太多其他地方。

这是一个人为的例子,但类似的情况在实际程序中经常出现。解决这些问题的最佳方法是什么?

最佳答案

根据您的偏好,您可以通过自己的设计注入(inject)“常量”值,这样您的单元测试就可以与实际上构成及格分数的变幻莫测的情况隔离开来。这样做的难易程度因编程语言而异。考虑将此代码用于一种使它变得简单的语言:

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 中的值设置为默认为常量的属性,或者甚至提供一个特殊版本的常量文件供您的单元测试使用。

如果没有真正强大的性能要求,我将选择上述方法,而不是让值成为一个真正的常量。只有当我找不到从单元测试中注入(inject)我想要的值的方法时,我才会使用通用定义的常量。我认为在几乎任何情况下你都不应该做的是复制这个测试中的常量,毕竟这是为了确保 Student逻辑是正确的。

关于unit-testing - 单元测试是否应该依赖于应用程序定义的常量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12356070/

相关文章:

c# - 如何使用最小起订量为单元测试设置服务器变量

docker - Laravel 与 Docker : wrong DB selected when testing

javascript - 测试 Vuetify (Vue.js) - 第二次调用 mount 抛出错误

performance - Web开发有没有像CAP这样的定理?

algorithm - 为什么回溯会使算法具有不确定性?

ios - 如何将核心数据用于主要应用程序和单元测试?

objective-c - 测试: Objective-C + Swift

javascript - 测试 AngularUI Bootstrap 模式实例 Controller

language-agnostic - 如何衡量代码库中的百分比差异?

windows - Windows 应用程序应使用哪些组合键以避免冲突?