简体   繁体   English

为什么只有在运行完整的测试套件时,django测试才会失败?

[英]why would a django test fail only when the full test suite is run?

I have a test in Django 1.5 that passes in these conditions: 我在Django 1.5中测试过这些条件:

  • when run by itself in isolation 独立运行时
  • when the full TestCase is run 当完整的TestCase运行时
  • when all of my app's tests are run 当我的所有应用程序的测试都运行时

But it fails when the full test suite is run with python manage.py test . 但是当使用python manage.py test运行完整的测试套件时,它会失败。 Why might this be happening? 为什么会发生这种情况?

The aberrant test uses django.test.Client to POST some data to an endpoint, and then the test checks that an object was successfully updated. 异常测试使用django.test.ClientPOST一些数据到一个端点,然后将测试检查该对象已成功更新。 Could some other app be modifying the test client or the data itself? 其他一些应用程序可以修改测试客户端或数据本身吗?

I have tried some print debugging and I see all of the data being sent and received as expected. 我尝试了一些打印调试,我看到所有数据都按预期发送和接收。 The specific failure is a does-not-exist exception that is raised when I try to fetch the to-be-updated object from the db. 特定的失败是当我尝试从db中获取要更新的对象时引发的不存在的异常。 Strangely, in the exception handler itself, I can query for all objects of that type and see that the target object does in fact exist. 奇怪的是,在异常处理程序本身中,我可以查询该类型的所有对象,并看到目标对象确实存在。

Edit: 编辑:

My issue was resolved when I found that I was querying for the target object by id and User and not id and UserProfile , but it's still confusing to me that this would work in some cases but fail in others. 当我发现我通过idUser而不是idUserProfile查询目标对象时,我的问题得到了解决,但是我仍然感到困惑的是,这在某些情况下会起作用但在其他情况下会失败。

I also found that the test would fail with python manage.py test auth <myapp> 我还发现使用python manage.py test auth <myapp>测试会失败

It sounds like your problem does not involve mocks, but I just spent all day debugging an issue with similar symptoms, and your question is the first one that came up when I was searching for a solution, so I wanted to share my solution here, just in case it will prove helpful for others. 听起来你的问题不涉及嘲讽,但我只是花了一整天调试一个有类似症状的问题,而你的问题是我在寻找解决方案时出现的第一个问题,所以我想在这里分享我的解决方案,以防它对别人有用。 In my case, the issue was as follows. 就我而言,问题如下。

I had a single test that would pass in isolation, but fail when run as part of my full test suite. 我有一个单独的测试可以隔离通过,但是作为我的完整测试套件的一部分运行时会失败。 In one of my view functions I was using the Django send_mail() function. 在我的一个视图函数中,我使用的是Django send_mail()函数。 In my test, rather than having it send me an email every time I ran my tests, I patch ed send_mail in my test method: 在我的测试,而不是它的每一个我跑我的测试时间发邮件给我,我patchsend_mail在我的测试方法:

from mock import patch
...

def test_stuff(self):
    ...

    with patch('django.core.mail.send_mail') as mocked_send_mail:

    ...

That way, after my view function is called, I can test that send_mail was called with: 这样,在调用我的视图函数后,我可以测试调用send_mail

self.assertTrue(mocked_send_mail.called)

This worked fine when running the test on its own, but failed when run with other tests in the suite. 这在单独运行测试时工作正常,但在套件中使用其他测试运行时失败。 The reason this fails is that when it runs as part of the suite other views are called beforehand, causing the views.py file to be loaded, causing send_mail to be imported before I get the chance to patch it. 这个失败的原因是当它作为套件的一部分运行时,事先调用其他视图,导致加载views.py文件,导致我有机会patch之前导入send_mail So when send_mail gets called in my view, it is the actual send_mail that gets called, not my patched version. 因此,当在我的视图中调用send_mail时,它是被调用的实际send_mail ,而不是我的修补版本。 When I run the test alone, the function gets mocked before it is imported, so the patched version ends up getting imported when views.py is loaded. 当我单独运行测试时,该函数在导入之前会被模拟,因此修补后的版本最终会在加载views.py时导入。 This situation is described in the mock documentation , which I had read a few times before, but now understand quite well after learning the hard way... 这种情况在模拟文档中有所描述,我之前已经阅读了几次,但是在学习了很多方法后现在理解得很好......

The solution was simple: instead of patching django.core.mail.send_mail I just patched the version that had already been imported in my views.py - myapp.views.send_mail . 解决方案很简单:我只修补了我在views.py - myapp.views.send_mail导入的版本,而不是修补django.core.mail.send_mail In other words: 换一种说法:

with patch('myapp.views.send_mail') as mocked_send_mail:
...

Try this to help you debug: 试试这个来帮助你调试:

./manage.py test --reverse

In my case I realised that one test was updating certain data which would cause the following test to fail. 在我的情况下,我意识到一个测试是更新某些数据,这将导致以下测试失败。

Another possibility is that you've disconnected signals in the setUp of a test class and did not re-connect in the tearDown. 另一种可能性是你在测试类的setUp中断开了信号,并且没有在tearDown中重新连接。 This explained my issue. 这解释了我的问题。

There is a lot of nondeterminism that can come from tests that involve the database. 有很多不确定性可以来自涉及数据库的测试。

For instance, most databases don't offer deterministic selects unless you do an order by. 例如,除非您按顺序执行,否则大多数数据库不提供确定性选择。 This leads to the strange behavior where when the stars align, the database returns things in a different order than you might expect, and tests that look like 这导致了奇怪的行为,当星星对齐时,数据库以不同于您预期的顺序返回事物,并且测试看起来像

result = pull_stuff_from_database()
assert result[0] == 1
assert result[1] == 2

will fail because result[0] == 2 and result[1] == 1 . 将失败,因为result[0] == 2 and result[1] == 1

Another source of strange nondeterministic behavior is the id autoincrement together with sorting of some kind. 另一个奇怪的不确定行为的来源是id自动增量和某种类型的排序。

Let's say each tests creates two items and you sort by item name before you do assertions. 假设每个测试都会创建两个项目,并在执行断言之前按项目名称进行排序。 When you run it by itself, "Item 1" and "Item 2" work fine and pass the test. 单独运行时,“项目1”和“项目2”正常工作并通过测试。 However, when you run the entire suite, one of the tests generates "Item 9" and "Item 10". 但是,当您运行整个套件时,其中一个测试会生成“第9项”和“第10项”。 "Item 10" is sorted ahead of "Item 9" so your test fails because the order is flipped. “项目10”在“项目9”之前排序,因此您的测试失败,因为订单被翻转。

So I first read @elethan's answer and went 'well this is certainly not my problem, I'm not patching anything'. 所以我首先阅读@ elethan的回答并且'好吧这肯定不是我的问题,我不修补任何东西'。 But it turned out I was indeed patching a method in a different test suite, which stayed permanently patched for the rest of the time the tests were run. 但事实证明,我确实在一个不同的测试套件中修补了一个方法,在测试运行的剩余时间里,该套件保持永久修补。

I had something of this sort going on; 我有类似的事情在继续;

send_comment_published_signal_mock = MagicMock()
comment_published_signal.send = send_comment_published_signal_mock

You can see why this would be a problem if some things are not cleaned up after running the test suite. 如果在运行测试套件后没有清理某些内容,您可以看到为什么这会出现问题。 The solution in my case was to use the helpful with to restrict the scope. 我的解决方案是使用help with来限制范围。

signal = 'authors.apps.comments.signals.comment_published_signal.send'
with patch(signal) as comment_published_signal_mock:
    do_your_test_stuff()

This is the easy part though, after you know where to look. 在您知道要去哪里之后,这很容易。 The guilty test could come from anywhere. 有罪的测试可能来自任何地方。 The solution to this is to run the failing test and other tests together until you find the cause, and then again, progressively narrowing it down, module by module. 解决方案是将失败的测试和其他测试一起运行,直到找到原因,然后再逐步将模块逐渐缩小。

Something like; 就像是;

./manage.py test A C.TestModel.test_problem
./manage.py test B C.TestModel.test_problem
./manage.py test D C.TestModel.test_problem

Then recursively, if for example B is the problem child; 然后递归地,如果例如B是问题孩子;

./manage.py test B.TestModel1 C.TestModel.test_problem
./manage.py test B.TestModel2 C.TestModel.test_problem
./manage.py test B.TestModel3 C.TestModel.test_problem

This answer gives a good explanation for all this. 这个答案给出了这一切的一个很好的解释。

This answer is in the context of django , but can really apply to any python tests. 这个答案是在django的上下文中,但可以真正适用于任何python测试。

Good luck. 祝好运。

This was happening to me too. 这也发生在我身上。

When running the tests individually they passed, but running all tests with ./manage.py test it failed. 当单独运行测试时,它们通过了,但是使用./manage.py test运行所有测试都失败了。

The problem in my case is because I had some tests inheriting from unittest.TestCase instead of from django.test.TestCase , so some tests were failing because there were registers on the database from previous tests. 在我的情况下的问题是因为我有一些测试继承自unittest.TestCase而不是django.test.TestCase ,因此一些测试失败,因为在先前的测试中数据库上有寄存器。

After making all tests inherit from django.test.TestCase this problem has gone away. 在使所有测试继承自django.test.TestCase这个问题就消失了。

I found the answer on https://stackoverflow.com/a/436795/6490637 我在https://stackoverflow.com/a/436795/6490637上找到了答案

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

相关问题 Django - 添加 TestCase 时完整的测试套件失败,但在注释掉时完整的测试套件通过。 单独运行时所有 TestCase 均通过 - Django - Full test suite failing when adding a TestCase, but full test suite passes when it is commented out. All TestCase pass when run individually 当我在Django中运行完整的测试套件时,我收到有关缺少MessageMiddleware的错误 - When I run the full test suite in Django, I get errors about missing MessageMiddleware 使 pytest 仅在完整的测试套件运行时需要代码覆盖 - Make pytest require code coverage only on full test suite run 我的Python测试套件文件覆盖率何时不会达到100%? - When would my Python test suite file coverage not be 100%? 当我运行测试套件时,出现TypeError错误,我无法理解为什么 - When I run my test suite I am getting a TypeError I am not able to understand why 如何仅运行测试套件中的特定方法 - How to run only specific method from test suite 如何仅运行测试套件中添加的测试用例而不是该类中可用的所有测试用例? - How to run only the test cases added in a test suite and not all the test cases available in the class? Django测试套件URL覆盖范围 - Django Test Suite URL Coverage Django集成测试应在失败时通过 - Django Integrated Test Passing When it Should Fail Django测试仅在模块单独运行时失败 - Django test failing only when its module is run individually
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM