简体   繁体   English

针对特定于实现的数据库使用情况进

[英]Unit testing on implementation-specific database usage

I'm trying to create unit tests for a function that uses database queries in its implementation. 我正在尝试为在其实现中使用数据库查询的函数创建单元测试。 My understanding of unit testing is that you shouldn't be using outside resources such as databases for unit testing, and you should just create mock objects essentially hard coding the results of the queries. 我对单元测试的理解是你不应该使用外部资源(如数据库)进行单元测试,你应该创建模拟对象,基本上是对查询结果进行硬编码。

However, in this case, the queries are implementation specific, and if the implementation would change, so would the queries. 但是,在这种情况下,查询是特定于实现的,如果实现将更改,查询也将更改。 My understanding is also that unit testing is very useful because it essentially allows you to change the implementation of your code whenever you want while being sure it still works. 我的理解是单元测试非常有用,因为它基本上允许您随时更改代码的实现,同时确保它仍然有效。

In this case, would it be better to create a database for testing purposes, or to make the testing tailored to this specific implementation and change the test code if we ever change the implementation? 在这种情况下,为了测试目的创建数据库,或者为这个特定的实现量身定制测试,如果我们改变实现,更改测试代码会更好吗?

Well, to start with, I think this is very much something that depends on the application context, the QA/dev's skill set & preferences. 好吧,首先,我认为这取决于应用程序上下文,QA / dev的技能组合和首选项。 So, what I think is right may not be right for others. 所以,我认为正确的做法可能不适合其他人。

Having said that... 话说回来...

In my case, I have a system where an extremely complex ERP database, which I dont control, is very much in the driver's seat and my code is a viewer/observer, rather than a driver of that database. 在我的情况下,我有一个系统,其中一个非常复杂的ERP数据库,我不控制,非常在驾驶员的位置,我的代码是一个查看器/观察者,而不是该数据库的驱动程序。 I don't, and can't really, use an ORM layer much, all my added value is in queries that deeply understand the underlying database data model. 我没有,也不能真正使用ORM层,我所有的附加值都在深入理解底层数据库数据模型的查询中。 Note also that I am mostly a viewer of that db, in fact my code has read-only access to the primary db. 另请注意,我主要是该数据库的查看者,实际上我的代码具有对主数据库的只读访问权限。 It does have write access to its own tagging database which uses the Django ORM and testing there is different in nature because of my reliance on the ORM. 它确实具有对其自己的标记数据库的写访问权,该数据库使用Django ORM并且由于我依赖于ORM而在性质上进行测试。

For me, it had better be tested with the database. 对我来说,最好用数据库进行测试。

Mock objects? 模拟对象? Please, mocking would have guzzled time if there is a lot of legitimate reasons to view/modify database contents with complex queries. 如果有很多合理的理由来查看/修改具有复杂查询的数据库内容,那么嘲笑就会耗费时间。

Changing queries . 更改查询 In my case, changing and tweaking those queries, which are the core of my application logic, is very often needed. 在我的例子中,经常需要更改和调整那些作为我的应用程序逻辑核心的查询。 So I need to make fully sure that they perform as intended against real data. 因此,我需要确保它们按照预期的方式执行实际数据。

Multi-platform concerns . 多平台问题 I started coding on postgresql, tweaked my connectivity libraries to support Oracle as well. 我开始在postgresql上编码,调整我的连接库以支持Oracle。 Ran the unit tests and fixed anything that popped up as an error. 完成单元测试并修复弹出的任何错误。 Would a database abstraction have identified things like the LIMIT clause handling in Oracle? 数据库抽象是否已经识别出Oracle中的LIMIT子句处理等内容?

Versioning . 版本控制 Again, I am not the master of the database. 同样,我不是数据库的主人。 So, as versions change, I need to hook up my code to it. 因此,随着版本的变化,我需要将代码连接到它。 The unit testing is invaluable, but that's because it hits the raw db. 单元测试是非常宝贵的,但这是因为它击中了原始数据库。

Test robustness . 测试稳健性 One lesson I learned along the way is to uncouple the test from the test db. 我在学习过程中学到的一个教训是将测试与测试数据库分开。 Say you want to test a function that flags active customers that have not ordered anything in a year. 假设您要测试一个功能,该功能可以标记一年内未订购任何内容的活跃客户。 My initial test approach involved manual lookups in the test database, find CUST701 to be a match to the condition. 我的初始测试方法涉及在测试数据库中进行手动查找,发现CUST701与条件匹配。 Then call my function and test if CUST701 is the result set of customers needing review. 然后调用我的函数并测试CUST701是否是需要审核的客户的结果集。 Wrong approach. 错误的做法。 What you want to do is to write, in your test, a query that finds active customers that have not ordered anything in a year. 您要做的是在测试中编写查询,查找未在一年内订购任何内容的活跃客户。 No hardcoded CUST701s at all, but your test query query can be as hardcoded as you want - in fact, it should look as little as your application queries as possible - you don't want your test sql to replicate what could potentially be a bug in your production code. 根本没有硬编码的CUST701,但是你的测试查询查询可以像你想要的那样硬编码 - 实际上,它应该看起来尽可能少的应用程序查询 - 你不希望你的测试sql复制可能是一个bug的东西在您的生产代码中。 Once you have dynamically identified a target customer meeting the criteria, then call your code under test and see if the results are as expected. 一旦您动态识别满足条件的目标客户,然后调用您的测试代码并查看结果是否符合预期。 Make sure your coverage tools identify when you've been missing test scenarios and plug those holes in the test db. 确保您的覆盖工具确定何时缺少测试方案并在测试数据库中插入这些漏洞。

BDD . BDD To a large extent, I am starting to approach testing from a BDD perspective, rather than a low-level TDD. 在很大程度上,我开始从BDD角度进行测试,而不是低级TDD。 So, I will be calling the url that handles the inactive customer lists, not testing individual functions. 因此,我将调用处理非活动客户列表的URL,而不是测试单个函数。 If the overall result is OK and I have enough coverage, I am OK, without wondering about the detailed low-level to and fro. 如果总体结果还可以,我有足够的覆盖率,我很好,不用担心详细的低级别来回。 So factor this as well in qualifying my answer. 因此,在考虑我的答案时也考虑到这一点。

Coders have always had test databases. 编码器一直有测试数据库。 To me, it seems logical to leverage them for BDD/unit-testing, rather than pretending they don't exist. 对我来说,将它们用于BDD /单元测试似乎是合乎逻辑的,而不是假装它们不存在。 But I am at heart a SQL coder that knows Python very well, not a Python expert who happens to dabble in SQL. 但我内心深处是一个非常了解Python的SQL编码器,而不是那些碰巧涉及SQL的Python专家。

As it seems I got the wrong end of the stick, I had a similarish problem and like you an ORM was not an option. 由于看起来我得到了错误的结束,我有一个类似的问题,像你一样,ORM不是一个选择。

The way I addressed it was with simple collections of Data Transfer objects. 我解决它的方式是简单的数据传输对象集合。 So the new code I wrote, had no direct access to the db. 所以我写的新代码没有直接访问数据库。 It did everything with simple lists of objects. 它使用简单的对象列表完成所有操作。 All the business logic and ui could be tested without the db. 所有业务逻辑和ui都可以在没有db的情况下进行测试。

Then I had an other module that did nothing but read and write to the db, to and from my collections of objects. 然后我有一个其他模块除了读取和写入数据库之外什么都没做,来往于我的对象集合。 It was a poor mans ORM basically, a lot of donkey work. 这是一个穷人的ORM基本上,很多驴工作。 Testing was run the db creation script, then some test helper code to populate the db with data I needed for each test. 测试运行db创建脚本,然后运行一些测试帮助程序代码,用每个测试所需的数据填充数据库。

Boring but effective, and you can with a bit of care, refactor it in to the code base without too much risk. 无聊但有效,你可以稍加小心,将其重构到代码库中而不会有太大的风险。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM