不同的测试方法
首先定义您正在做什么:单元测试或集成测试。层数与单元测试无关,因为您最有可能只测试一个类。剩下的你嘲笑。对于集成测试,不可避免地要测试多个层。如果您有良好的单元测试,则诀窍是使集成测试不太复杂。
如果您的单元测试很好,那么在进行集成测试时不必重复测试所有细节。
我们使用的术语有点依赖于平台,但是您几乎可以在所有测试/开发平台中找到它们:
应用范例
根据您使用的技术,名称可能会有所不同,但是我将以此为例:
如果您有一个简单的CRUD应用程序,其模型为Product,ProductsController和一个索引视图,该视图生成包含产品的HTML表:
该应用程序的最终结果是显示一个HTML表,其中包含所有活动产品的列表。
单元测试
模型
您可以轻松测试的模型。有不同的方法。我们使用固定装置。我认为这就是您所说的“伪数据集”。因此,在运行每个测试之前,我们先创建表,然后放入原始数据。大多数平台都有用于此的方法。例如,在您的测试类中,有一个方法setUp()在每个测试之前运行。
然后,我们运行测试,例如:testGetAllActive产品。
因此,我们直接测试到测试数据库。我们不模拟数据源;我们使它始终相同。例如,这使我们可以测试数据库的新版本,并且会出现任何查询问题。
在现实世界中,您不能总是遵循100%的单一责任。如果您想做得更好,可以使用模拟的数据源。对我们来说(我们使用ORM)就像测试现有技术一样。而且测试变得更加复杂,并且它们实际上并没有测试查询。所以我们保持这种方式。
硬编码数据分别存储在灯具中。因此,固定装置就像一个带有创建表语句的SQL文件,并为我们使用的记录插入。除非确实需要对大量记录进行测试,否则我们将它们保持在很小的范围内。
class ProductModel {
public function getAllActive() {
return $this->find('all', array('conditions' => array('active' => 1)));
}
}
控制者
控制器需要做更多的工作,因为我们不想用它来测试模型。因此,我们要做的是模拟模型。这意味着:我们测试:index()方法,该方法应返回记录列表。
因此,我们模拟了模型方法getAllActive()并在其中添加了固定数据(例如,两条记录)。现在,我们测试控制器发送到视图的数据,并比较是否确实获得了这两个记录。
function testProductIndexLoggedIn() {
$this->setLoggedIn();
$this->ProductsController->mock('ProductModel', 'index', function(return array(your records) ));
$result=$this->ProductsController->index();
$this->assertEquals(2, count($result['products']));
}
够了 我们尝试向控制器添加尽可能少的功能,因为这会使测试变得困难。但是,当然总会有一些代码。例如,我们测试需求,例如:仅在登录时才显示这两个记录。
因此,控制器通常需要一个模拟文件和一小部分硬编码数据。对于登录系统,可能是另一个。在我们的测试中,我们有一个辅助方法:setLoggedIn()。这使登录或不登录的测试变得简单。
class ProductsController {
public function index() {
if($this->loggedIn()) {
$this->set('products', $this->ProductModel->getAllActive());
}
}
}
观看次数
视图测试很难。首先,我们分离出重复的逻辑。我们将其放在Helpers中,并严格测试这些类。我们期望总是相同的输出。例如,generateHtmlTableFromArray()。
然后,我们有一些项目特定的视图。我们不测试那些。真正不需要对它们进行单元测试。我们保留它们进行集成测试。由于我们将大量代码提取到视图中,因此此处的风险较低。
如果您开始进行测试,则每次更改一段HTML对大多数项目都没有用时,您可能需要更改测试。
echo $this->tableHelper->generateHtmlTableFromArray($products);
整合测试
根据这里的平台,您可以处理用户故事等。它可以基于网络,例如Selenium或其他类似的解决方案。
通常,我们只是使用固定装置加载数据库,并断言哪些数据应该可用。对于全面集成测试,我们通常使用非常全局的要求。因此:将产品设置为活动状态,然后检查该产品是否可用。
我们不会再次测试所有内容,例如是否提供正确的字段。我们在这里测试更大的要求。由于我们不想从控制器或视图复制测试。如果某些内容确实是您应用程序的关键/核心部分,或者出于安全原因(请检查密码不可用),则我们添加它们以确保它是正确的。
硬编码数据存储在灯具中。
function testIntegrationProductIndexLoggedIn() {
$this->setLoggedIn();
$result=$this->request('products/index');
$expected='<table';
$this->assertContains($expected, $result);
// Some content from the fixture record
$expected='<td>Product 1 name</td>';
$this->assertContains($expected, $result);
}