我正在尝试了解涉及数据库时的单元测试。我的课程很大程度上依赖于数据库来完成他们的工作。我已经在stackoverflow和一般的互联网上看了很多答案,但我对我发现的东西并不满意。
当涉及数据库时(我的情况是MySQL),我看到的一个常见问题是测试真的很长,而且一种可能的解决方案是使用SQLite。
我无法在测试中的任何地方使用它,因为有些类使用RAW查询而不是Doctrine querybuilder来绕过未知日期时间函数的限制。 SQLite对日期值有一组不同的函数,这意味着要在测试中使用它,我应该重写我的查询两次,一次用于MySQL,一次用于SQLite。
我决定坚持使用MySQL,但每次测试运行时创建和删除模式需要花费很多时间。我知道SchemaTool类可以处理模式子集的创建:如果只创建我在测试套件中真正需要的表,或者我应该总是使用完整的模式,那么这将是一个很好的解决方案吗?
代码部分示例(伪代码)我正在尝试测试
NotificationManagerClass
constructor(EntityManager)
loadNotifications()
deleteNotification()
updateNotification()
如您所见,我将实体管理器注入到类的构造函数中。该类是在Symfony容器中注册的服务。然后在控制器中我获得此服务并使用其方法。在方法内部,我使用querybuilder,因为我必须能够访问其他一些服务,并且存储库不是容器感知的。我怎样才能解除比我班级更多的问题呢?我无法想办法做到这一点
答案 0 :(得分:4)
你把很多单词混合在一起,这些单词并不都具有你给他们的意思。快速摘要的单词:
你不能模仿一切,因为你决定使用原始的mysql函数(糟糕的选择)...总是避免在类中使用mysql查询。使用Doctrine(有很多简单的方法来绕过未知的日期时间函数)或将原始查询放在Repository中并模拟存储库。
简而言之:
答案 1 :(得分:2)
涉及数据库的测试不是单元测试。您的存储库应该使用集成或功能测试进行测试(如果您这样做,则接受测试)。
如果您有许多涉及数据库的测试,这可能意味着您在某处出现了错误的转弯:
可能值得研究测试金字塔:http://martinfowler.com/bliki/TestPyramid.html
通过研究如何加快测试速度,你只能继续走错路。解决方案是编写更多的单元测试和更少的集成测试。单元测试快速,独立且隔离,因此难以破解。集成测试更加脆弱和缓慢。查看FIRST properties of unit tests。
顺便说一句:SQLite是一个死胡同。它的行为与mysql不同,因为它不支持约束。
您的示例类可以建模为:
class NotificationManager
{
public function __construct(MyNotificationRepository $repository, MyFabulousService $service)
{}
// ... other methods
}
通过这种方式,您可以注入存储库和服务的假货,并单独测试NotificationManager。
单元测试查询构建器没有多大价值,因为您要测试的是doctrine而不是代码。它也很难,因为查询类被声明为final。您可以测试查询是否在功能上返回正确的结果。如果你正确地测试你的课程,那么所需的功能测试就会少得多。
如果你将MyNotificationRepository作为一个界面,你甚至可以从教义中解脱出来。