共享单元测试夹具

6
我正在为一个项目编写单元测试(使用PHPUnit编写的PHP代码),该项目将其整个环境(加载的组件、事件、配置、缓存、每个环境的单例等)保存在一个对象中,所有组件都使用该对象相互交互(使用中介者模式)。
为了使单元测试运行更快,我在同一测试用例中共享环境对象和其他一些对象(例如,在我的视图对象的测试用例中,视图管理器对象[作为视图对象的工厂并负责实际渲染])(使用PHPUnit的setUpBeforeClass()和静态属性)。
尽管据我所知,我分享的对象不应影响测试的完整性(例如,在视图情况下,共享环境和视图管理器对象,但是为每个测试创建单独的视图对象 - 这是实际由测试用例测试的对象),但这让我感觉越来越不对劲。
我希望每个测试都使用完全隔离的环境,并且不能以任何方式影响同一测试用例中的其他测试。然而,这会使测试运行速度变慢,感觉为了一些我无法准确指出缺点的东西而付出了很大的代价,主要只是“感觉不对”。
你怎么看?您能否指出任何缺点,以便我可以说服自己它值得更长的执行时间?还是我反应过度了,这完全没问题?

你能否定义一些“测试配置文件”呢?这样你就不必每次都运行所有的测试了。这样,你可以每天运行“完整测试”配置文件一次,并为当前正在进行的工作使用一个更小、更易管理的配置文件。 - Quamis
抱歉 - 我有点忘记给赏金了。我想当它过期时就会消失,没有人会得到它吧?我正在开始另一个并将其交给威利,但我希望我可以分割它,因为所有答案都非常有用。谢谢大家! 更新 看起来我只能在24小时后给予赏金 - 希望我不会在那时忘记它 :-) - shesek
3个回答

5
我理解您的感受,也许我可以陈述一下当我遇到此问题时的目标和解决方案:

  • 开发人员应该拥有能够非常快速运行的测试套件
  • 至少单个测试用例应该在不到一秒钟的时间内执行
  • 确实想要确保我的测试用例中没有相互依赖的情况

我假设您正在运行持续集成服务器。如果没有,则可以考虑设置一个cron任务,但是请考虑设置jenkins,它非常容易设置,真的很容易


对于普通用途:

只需分享所需的夹具即可获得所需的速度。这可能不太美观,并且可能会有更好的解决方案,但是如果您有某些昂贵的内容需要创建,请只创建一次。

我建议使用helper方法getFoo() { if(!self::$foo) .... create ... return $foo;} 而不是setUpBeforeClass,因为它可以使共享变得更容易,但主要是因为以下原因。

每晚一次:

使用--process-isolation运行测试套件并在引导时重新创建完整的数据库和所有内容。

它可能需要运行6小时(为此禁用代码覆盖率!),但是无论如何都可以。您的夹具将为每个单独的测试用例重新创建,因为它是一个新的php进程,静态变量不存在。


使用此方式,您可以确保您不会在每天创建依赖项。这已经足够好,可以记住您所做的事情(如果需要修复某些内容,则可以使用--filter和--process-isolation运行)。


我不太明白setUpBeforeClass和你建议的getter函数之间有什么区别。我唯一看到的区别是,getter方法只会在第一次请求时创建对象,而setUpBeforeClass总是会创建它们。这对于“每晚一次”的点有什么影响呢? - shesek
谢谢你提供Jenkins的建议。我想尝试一下Bitten,因为它应该可以很好地与Trac配合使用(我已经使用了相当长的时间,并且非常满意),但似乎它还不够稳定,所以我可能会选择Jenkins。 - shesek
@shesek 抱歉回答晚了,我出城了。简而言之:如果您在某个时间点需要在不同的测试类中使用夹具,则这些辅助方法将使帮助更加容易。如果创建它们真的很昂贵,也许您的套件只需要一个?如果这还不能完全回答您的问题,也许我可以提供更多的例子。 - edorian

2

就像编写“普通”代码一样,当你编写测试用例时,依靠对装置对象的工作原理的了解是可以的。

如果某个给定的工厂方法被记录为每次生成新实例,则每次创建工厂方法只会带来缺点,特别是如果工厂创建本身很昂贵。

在编写单元测试时,记住一个关键目标是有助于提高测试的全面性。你想在5-10分钟内知道是否破坏了构建。这样,你就可以在得到“全清”之后去吃午饭、开会、回家等。如果你知道某个装置的某些部分可以重复使用而不产生交互,那么你应该利用这个知识,在这个5-10分钟的时间窗口内使你的测试更加全面。我理解这里的纯粹主义冲动,但它在测试独立性方面并没有任何好处,并且无意中限制了你的测试套件所能为你完成的任务。


1

也许这是亵渎的,但如果您仍然可以管理重要的代码覆盖率,并且还可以保证不存在状态污染(这才是您真正的问题 - 您是否确保每个测试不会受到上一个测试留下的数据的影响),那么我认为不需要改变现状。

让测试快速运行,当发现错误时(这在集成测试中是不可避免的),然后您有理由投入时间来定位特定的测试或一组测试。但是,如果您有适用于一般情况的工具包,则应将其保留为原样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接