PHPUnit 测试无构造函数 class
PHPUnit testing constructorless class
我正在为一个项目开发单元测试,我遇到了一个不包含构造函数的 class。
你可能会问自己,"How does this object exist then?"
嗯,在另一个系统中,这个对象被生成并保存在数据库中,所以在需要单元测试的系统中,没有为那个定义构造函数class。但是需要测试它们的功能,这样如果以后在系统中修改了它们,测试会指出它们是在什么情况下使用的,这样可以确保我不会忽略项目中使用它的其他点。
在这种环境下,如何测试这种class?
我尝试使用模拟,但模拟带来了所有空属性。此外,模拟对象仅作为您之前所说的函数的结果出现。所以要测试对象本身的功能,这个是没有功能的。
有什么想法吗?
PS: 抱歉英语不好。
构造函数是可选的。 class 不需要构造函数即可实例化它或测试其方法是否正常运行。
据我了解,您想测试一种根据特定 属性 表现不同的方法,这通常由构造函数设置,但在您的 class 中不是。这意味着在实际代码使用中,属性 可能在某些时候直接设置,或者有不同的方法设置它的值。
一般来说,为了测试这些类型的方法,您应该始终自己设置这样的 属性。原因很简单:单个测试应该 只 测试一种特定方法。如果您依赖构造函数,那么您的测试将测试构造函数和该方法的 组合 。您对该方法的测试将取决于构造函数是否正常运行。
想象一下:
class Mood {
public $happy;
function __construct() {
$this->happy = true;
}
public function greet() {
if ($this->happy) {
return 'Hi!';
} else {
return 'Go away';
}
}
}
假设您想测试 greet()
方法的行为:
class MoodTest extends \PHPUnit\Framework\TestCase {
public function testGreet() {
$mood = new Mood();
$this->assertEqual('Hi!', $mood->greet())
}
}
此测试会通过,因为我们假设 构造函数正在执行其工作并将$happy
属性 设置为true
。但是这里有两个问题:
- 如果
$happy
是 false
,我们不会测试该方法是否正常工作
- 我们依靠构造函数将
$happy
的初始值设置为true
这意味着事情可能会在我们的控制之外发生变化,这会破坏这个特定的测试,即使该功能仍然按预期工作。业务逻辑可能会更改,因此构造函数最初会将 $happy
设置为 false
。或者开发人员的逻辑可能会改变构造函数完全消失并以其他方式设置 $happy
(可能在某个时候引入 setHappy()
方法)。
要正确测试 greet()
方法,应该对每种可能的结果进行测试。在这种情况下,该方法只有一个 if
语句,因此应该有一个针对该条件的两个结果的测试用例:
class MoodTest extends \PHPUnit\Framework\TestCase {
public function testGreetIfHappy() {
$mood = new Mood();
$mood->happy = true;
$this->assertEqual('Hi!', $mood->greet())
}
public function testGreetIfNotHappy() {
$mood = new Mood();
$mood->happy = false;
$this->assertEqual('Go away', $mood->greet())
}
}
现在,无论构造函数或业务逻辑发生什么变化,这些测试都仅测试greet()
方法的行为。构造函数正在做的任何其他事情(即使不存在或根本不做任何事情)都不再对 greet()
方法的测试产生任何影响。
我正在为一个项目开发单元测试,我遇到了一个不包含构造函数的 class。
你可能会问自己,"How does this object exist then?"
嗯,在另一个系统中,这个对象被生成并保存在数据库中,所以在需要单元测试的系统中,没有为那个定义构造函数class。但是需要测试它们的功能,这样如果以后在系统中修改了它们,测试会指出它们是在什么情况下使用的,这样可以确保我不会忽略项目中使用它的其他点。
在这种环境下,如何测试这种class?
我尝试使用模拟,但模拟带来了所有空属性。此外,模拟对象仅作为您之前所说的函数的结果出现。所以要测试对象本身的功能,这个是没有功能的。
有什么想法吗?
PS: 抱歉英语不好。
构造函数是可选的。 class 不需要构造函数即可实例化它或测试其方法是否正常运行。
据我了解,您想测试一种根据特定 属性 表现不同的方法,这通常由构造函数设置,但在您的 class 中不是。这意味着在实际代码使用中,属性 可能在某些时候直接设置,或者有不同的方法设置它的值。
一般来说,为了测试这些类型的方法,您应该始终自己设置这样的 属性。原因很简单:单个测试应该 只 测试一种特定方法。如果您依赖构造函数,那么您的测试将测试构造函数和该方法的 组合 。您对该方法的测试将取决于构造函数是否正常运行。
想象一下:
class Mood {
public $happy;
function __construct() {
$this->happy = true;
}
public function greet() {
if ($this->happy) {
return 'Hi!';
} else {
return 'Go away';
}
}
}
假设您想测试 greet()
方法的行为:
class MoodTest extends \PHPUnit\Framework\TestCase {
public function testGreet() {
$mood = new Mood();
$this->assertEqual('Hi!', $mood->greet())
}
}
此测试会通过,因为我们假设 构造函数正在执行其工作并将$happy
属性 设置为true
。但是这里有两个问题:
- 如果
$happy
是false
,我们不会测试该方法是否正常工作
- 我们依靠构造函数将
$happy
的初始值设置为true
这意味着事情可能会在我们的控制之外发生变化,这会破坏这个特定的测试,即使该功能仍然按预期工作。业务逻辑可能会更改,因此构造函数最初会将 $happy
设置为 false
。或者开发人员的逻辑可能会改变构造函数完全消失并以其他方式设置 $happy
(可能在某个时候引入 setHappy()
方法)。
要正确测试 greet()
方法,应该对每种可能的结果进行测试。在这种情况下,该方法只有一个 if
语句,因此应该有一个针对该条件的两个结果的测试用例:
class MoodTest extends \PHPUnit\Framework\TestCase {
public function testGreetIfHappy() {
$mood = new Mood();
$mood->happy = true;
$this->assertEqual('Hi!', $mood->greet())
}
public function testGreetIfNotHappy() {
$mood = new Mood();
$mood->happy = false;
$this->assertEqual('Go away', $mood->greet())
}
}
现在,无论构造函数或业务逻辑发生什么变化,这些测试都仅测试greet()
方法的行为。构造函数正在做的任何其他事情(即使不存在或根本不做任何事情)都不再对 greet()
方法的测试产生任何影响。