单元测试功能有副作用?

时间:2010-08-28 03:20:29

标签: unit-testing redirect controller separation-of-concerns side-effects

假设您正在编写一个函数来检查是否通过相应的URL访问了某个页面。该页面有一个“规范”存根 - 例如,虽然可以通过stackoverflow.com/questions/123访问页面,但我们更愿意(出于搜索引擎优化的原因)将其重定向到stackoverflow.com/questions/123/how-do -i-move-the-turtle-in-logo - 实际的重定向安全地包含在自己的方法中(例如redirectPage($ url)),但是如何正确测试调用它的函数?

例如,请执行以下功能:

function checkStub($questionId, $baseUrl, $stub) {
  canonicalStub = model->getStub($questionId);
  if ($stub != $canonicalStub) {
    redirectPage($baseUrl . $canonicalStub);
  }
}

如果您要对checkStub()函数进行单元测试,重定向不会妨碍吗?

这是一个更大的问题的一部分,其中某些功能似乎变得太大并且离开了单元测试的领域并进入了集成测试的世界。我的想法立即认为路由器和控制器存在这些问题,因为测试它们必然导致页面的生成,而不仅仅局限于它们自己的功能。

我是否在单元测试中失败了?

3 个答案:

答案 0 :(得分:2)

你说......

  

这是一个更大问题的一部分,其中某些功能似乎变得太大并且离开了单元测试的领域并进入了集成测试的世界

我认为这就是为什么单元测试很难(1)和(2)导致代码在自身重量下不会崩溃的原因。您必须一丝不苟地打破所有依赖关系,否则最终会进行单元测试==集成测试。

在您的示例中,您将注入重定向器作为依赖项。你使用模拟,双重或间谍。然后你按照@atk的规定进行测试。有时它不值得。更常见的是,它会迫使您编写更好的代码。如果没有IOC容器,很难做到。

答案 1 :(得分:1)

这是一个老问题,但我认为这个答案是相关的。 @Rob声明你会注入一个重定向器作为依赖 - 当然,这是有效的。但是,您的问题是您没有很好的分离关注点。

您需要使您的函数尽可能原子化,然后使用您创建的粒度函数组合更大的功能。你写了这个:

function checkStub($questionId, $baseUrl, $stub) {
  canonicalStub = model->getStub($questionId);
  if ($stub != $canonicalStub) {
    redirectPage($baseUrl . $canonicalStub);
  }
}

我写这个:

  function checkStubEquality($stub1, $stub2) {
    return $stub1 == $stub2;
  }

  canonicalStub = model->getStub($questionId);
  if (!checkStubEquality(canonicalStub, $stub)) redirectPage($baseUrl . $canonicalStub);

答案 2 :(得分:0)

听起来你只是有另一个测试用例。您需要检查存根是否正确识别为包含正面和负面测试的存根,并且您需要检查重定向到的页面是否正确。

或者我完全误解了这个问题?