想象一下,您拥有以下架构和数据:
create table test (
id serial primary key,
x integer not null,
y integer not null
);
insert into test (x, y) values (1, 2), (3, 4), (5, 6), (7, 8);
如果我想以插入的顺序获取test
的值,我可以使用:
select * from test order by id;
如果order by id
不存在(例如,red/green/refactor之后),我想写一个失败的单元测试。
我的失败的测试会:
test
。select * from test
的方法并返回数据(将此更改为select * from test order by id
应该使测试通过。)id
的顺序)。但是,此测试有可能返回误报(这通常是表格中没有任何索引的情况)。 order of a query without order by
is unspecified。
我想到的一个解决方案是使用id
的序列进行黑客攻击,以便id
以奇数顺序生成...但这感觉就像是一个黑客只是为了使这个测试可能。
编辑:好吧,似乎有些混乱。我知道如果没有order by
(我甚至引用了文档),订单就无法保证。我无法更改查询的表/视图。我正在修复今天不使用order by id
的方法中的错误。但是,我们知道此方法应该使用order by id
。因此,我需要更改代码以使用order by id
。在我这样做之前,我想编写一个单元测试来重现这个bug(方法的结果不按id
排序)。事实上,Postgres正在返回按id
排序的数据,因为我猜测数据是按插入顺序从磁盘上传出的。这在测试中创建了一个误报:当它应该失败时,传递。我想消除误报:在我修复bug之前它应该可靠地失败。
答案 0 :(得分:2)
但是,此测试有可能返回误报(这通常是表格中没有任何索引的情况)。
然后在桌面上添加一些索引!据推测,您正在使用自己为这个单元测试实例创建的小数据库,这个数据库将被吹走,随心所欲地做任何事情。索引不会更改查询的保证结果,并且不保证order by
订单无法保证其性能。所以这是对环境的安全改变。
我想到的一个解决方案是使用id的序列进行黑客攻击,以便以奇怪的顺序生成id ...但这只是为了进行此测试可能的。
单元测试通常会使正常的最佳实践规则陷入困境。在这种情况下,它正在设置您的测试数据,以避免误报。这与创建测试文件没有什么不同,只是为了测试方法中的罕见错误。虽然这使得测试glassbox因为它在存储机制的引擎盖下窥视,但这是一个有效的单元测试技术,用于详细说明。
从序列所在的位置开始。
select last_value from test_id_seq;
然后从那里开始(让我们说出来的话)。
insert into test (id, x, y) values (10, 1, 2), (12, 3, 4), (11, 5, 6), (9, 7, 8);
这会使序列混淆,接下来的几个插入将失败,因此您必须确保通过重新启动序列将其重新置于正轨。
alter sequence test_id_seq restart with 12;
如果其他进程同时与同一个数据库通信,我非常确定这不安全,但这在单元测试中并不重要。在测试结束时把桌子吹走。
同样,尝试删除一些行,然后插入更多行。
因为没有order by
的 没有保证结果顺序,所以即使以这种方式扰乱数据也不能保证正常工作。相反,迭代各种技术,直到您的数据不按顺序返回。像这样:
def test_ordering
while `select * from test` is ordered by id
if we've tried too may times
warn and go ahead anyway
end
perturb the data in test
end
assert obj.method is in id order
end
这是你能做的最好的事情。在某一点上,你必须减少损失。
答案 1 :(得分:0)
您无法从查询结果中判断该查询是否包含ORDER BY
。
只有在ORDER BY
中指定此顺序时,才能保证查询以特定顺序返回行。因此,您的初始假设是错误的,并且无法查看查询的结果并从中确定是否应用了ORDER BY
。 ORDER BY
可能会丢失,正确的行顺序只是巧合。
即使你想欺骗它并从排序视图中选择,这也无济于事。如果您在select * from test order by id desc
上创建了一个视图,然后检查此视图上的查询是否返回 asccending 行,那么这将没有任何意义,因为
select * from test_view;
基本上是
select * from (select * from test order by id desc);
因此您可以从派生表中进行选择,根据定义,派生表本身也是一组无序数据(即内部的ORDER BY
子句对结果没有保证效果。)