我正在编写一个项目的单元测试(用PHP编写,使用PHPUnit),它的整个环境(加载的组件,事件,配置,缓存,每个环境的单例等)都保存在一个对象中,所有组件都是用于相互交互(使用中介模式)。
为了使单元测试运行得更快,我正在共享环境对象和其他一些对象(例如,在我的测试用例中用于视图对象[如在MVC中的V],视图管理器对象[其中]充当视图对象的工厂并负责实际渲染])在同一测试用例中的测试中(使用PHPUnit的setUpBeforeClass()
和静态属性)。
尽管如此,据我所知,我共享的对象不应影响测试的完整性(例如,在视图的情况下,环境和视图管理器对象是共享的,但是单独的视图对象是为每个测试创建 - 这是测试用例实际测试的对象),它对我来说感觉越来越不对。
如果每个测试使用完全隔离的环境并且无法以任何方式影响同一测试用例中的其他测试,我更愿意这样做。然而,这会使测试运行得慢得多,感觉价格很高,我无法确定其缺点,主要是“感觉不对”。
你怎么看?你能否指出任何缺点,以便我可以说服自己值得更长的执行时间?或者我只是过度反应而且完全没问题?答案 0 :(得分:5)
我分享你的感受所以也许我只是在遇到这个问题时陈述我的目标和解决方案:
我将假设您正在运行Continuous Integration Server。如果不是cronjob可能会考虑设置jenkins,那就是really really easy。
只需分享尽可能多的灯具即可获得所需的速度。它可能不是很漂亮,可能会有更好的解决方案,但如果你有一些昂贵的东西,只需要做一次。
我建议帮助方法getFoo() { if(!self::$foo) .... create ... return $foo;}
超过setUpBeforeClass
,因为它可以让分享变得更容易,但主要是因为以下几点。
使用--process-isolation运行测试套件,并在该引导程序中重新创建完整的数据库和所有内容。
它可能会运行6个小时(禁用代码覆盖率!)但是如何关心。您的夹具将为每个测试用例重新创建,因为它是一个新的PHP进程,并且静态变量不存在。
使用这种方式,您可以确保每天都没有创建依赖项。这足以记住你做了什么(如果你需要修复一些东西,你可以运行--filter和--process-isolation)。
答案 1 :(得分:2)
与编写“普通”代码一样,在编写测试用例时,可以依赖于夹具对象的工作原理。
如果给定的工厂方法记录为每次都生成新实例,那么我每次都会重新创建工厂方法,特别是如果工厂创建本身很昂贵。
有助于牢记编写单元测试的关键目标。你想在5-10分钟内知道你是否破坏了构建。这样你就可以出去吃午饭,去参加会议,回家等等。如果您知道夹具的某些部分可以重复使用而不创建交互,那么您应该使用该知识在5-10分钟的窗口内使测试更加全面。我理解这里的纯粹主义冲动,但它在测试独立性方面没有给你带来任何好处,并且不必要地限制了你的测试套件将为你完成的任务。
答案 2 :(得分:1)
也许这是亵渎神明的,但如果你仍然可以管理一个重要的代码覆盖率阈值,你也可以保证不存在任何国家污染(这是你的真正问题 - 你是否确保每个测试都不会受到之前测试遗留下来的数据的影响,我认为将事情保持原样是没有问题的。
让测试快速运行,并且当发现错误时(这在集成测试中是不可避免的),那么您有理由将时间投入到本地化一个特定测试或一组测试中。但是,如果你有一个适用于一般情况的工具包,我会保持原样。