2

ユーザーがForeignKeyを特定の値に変更できるかどうかを確認するDjangoアプリを非常にカスタマイズしました。

この場合、 aは aUserに属しWorkgroup、 anItemもaWorkgroupに属することができるため、 aUserが anを作成するとき、それらは自分が属する s にItemのみ入れることができます。WorkgroupややこしいItemのは親クラスなので「アイテム」の種類が多い。

現在、これを確認するためのカスタム管理フォームのセットアップがあります。

class AdminConceptForm(autocomplete_light.ModelForm):
    def __init__(self, *args, **kwargs):
        #... other code
        self.fields['workgroup'].queryset = self.request.user.profile.editable_workgroups.all()

このテストの重要な部分は次のとおりです。

def setUp(self):
    from django.test import Client

    self.client = Client()
    self.wg1 = models.Workgroup.objects.create(name="Test WG 1") # Editor is member

def test_editor_change_item(self):
    self.login_editor()
    response = self.client.get(reverse("admin:%s_%s_change"%(self.itemType._meta.app_label,self.itemType._meta.model_name),args=[self.item1.pk]))
    self.assertResponseStatusCodeEqual(response,200)

    updated_item = dict((k,v) for (k,v) in model_to_dict(self.item1).items() if v is not None)
    updated_name = updated_item['name'] + " updated!"
    updated_item['name'] = updated_name

    updated_item.update({
        'statuses-TOTAL_FORMS': 0, 'statuses-INITIAL_FORMS': 0 #no statuses
    })
    updated_item.update(self.form_defaults)
    self.assertTrue(self.wg1 in self.editor.profile.myWorkgroups)

    self.assertEqual([self.wg1],list(response.context['adminform'].form.fields['workgroup'].queryset))

    self.assertTrue(perms.user_can_edit(self.editor,self.item1))
    self.assertTrue(self.item1.workgroup in self.editor.profile.editable_workgroups.all())

    response = self.client.post(
            reverse("admin:%s_%s_change"%(self.itemType._meta.app_label,self.itemType._meta.model_name),args=[self.item1.pk]),
            updated_item
            )

# HERE IS WHERE THE FAILURE IS!!!
    self.assertResponseStatusCodeEqual(response,302)

    self.item1 = self.itemType.objects.get(pk=self.item1.pk)
    self.assertEqual(self.item1.name,updated_name)

しかし、ときどき (そして断続的に)、テスト スイートを実行すると、postこのフォームでコンテンツの保存をテストすると、次のエラーが発生します。

======================================================================
FAIL: test_editor_change_item (aristotle_mdr.tests.test_extension_api.QuestionAdmin)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/travis/build/aristotle-mdr/aristotle-metadata-registry/aristotle_mdr/tests/test_admin_pages.py", line 285, in test_editor_change_item
    self.assertResponseStatusCodeEqual(response,302)
  File "/home/travis/build/aristotle-mdr/aristotle-metadata-registry/aristotle_mdr/tests/utils.py", line 501, in assertResponseStatusCodeEqual
    self.assertEqual(response.status_code, code)
AssertionError: 200 != 302

この性質上、正常に投稿された場​​合、ページリダイレクトされます。そうでない場合は、応答 HTML を吐き出すだけのコードがいくつかあります。その場合、次のようになります。

<label class="required" for="id_workgroup">Workgroup</label>
<select id="id_workgroup" name="workgroup">
    <option value="">---------</option>
    <option value="17" selected="selected">Test WG 1</option>
</select>
<ul class="errorlist">
    <li>workgroup instance with pk 17 does not exist.</li>
</ul>

ただし、このエラーが発生した場合、すべての項目タイプがエラーをスローするわけではなく、1 つまたは 2 つのみです。selectしかし、フィールドを見ると、id(またはpk)のワークグループ17が存在します。さらに、テスト スイートを再実行すると問題なく実行されます (「ウォームアップ」が数回行われる場合があります)。また、テスト以外のサイトでこれに遭遇したことはありません。

これは、Django テストがトランザクションに保持される方法が原因であると思いますか? 以前は非常に断続的でしたが、今ではより頻繁になっていますが、それでもランダムであるため、私はこれに悩まされ始めています。


したがって、これはまだ失敗しており、何が修正されていないかを言うことができます:

  • インメモリの代わりにファイルベースの SQLite インスタンスを使用する
  • テストに PostgreSQL を使用する
  • TestCase から TransactionTestCase への切り替え

私が知っていること:

  • 開発サーバーではテストは正常に実行されますが、Travis-CI では同じテストが失敗します
  • テスト Web クライアントへの呼び出しだけでなく、他のいくつかのクエリセットも機能します
  • トランザクションベースかもしれませんが、よくわかりません。

そして、非常に好奇心旺盛な人のために、ここに私が鎮圧しようとしているができない問題があります。


編集: 2015-06-11

失敗する自己完結型の例を作成しました!! SQLite は一貫して機能し、Postgres は一貫して失敗します。

何らかの理由で、このコードは一貫して悪いようです:

    def test_bar(self):
        # This test will always work
        print("Do Bar")
        self.do_foo()
        print("Bar done")
    def test_foo(self):
        # This test will always work
        print("Do Foo")
        self.login_editor()
        response = self.client.get(reverse("admin:%s_%s_changelist"%(self.itemType._meta.app_label,self.itemType._meta.model_name)))
        self.assertResponseStatusCodeEqual(response,200)
        self.do_foo()
        print("Foo done")
    def test_zip(self):
        # This test will always FAIL
        print("Do Zip")
        self.do_foo()
        print("Zip done")

実際、管理ビューを呼び出すと、changelistWorkgroupクエリセットに表示されなくなったため、保存しようとすると、Postgres で後続の管理ページが常に失敗します。さて、それはなぜですか?

完全なコード:

class MinimalExample(TestCase):
    itemType=models.ObjectClass
    form_defaults = {}
    create_defaults = {}
    def setUp(self):
        self.wg1 = models.Workgroup.objects.create(name="Test WG")

        self.editor = User.objects.create_user('eddie','','editor')
        self.editor.is_staff=True
        self.editor.save()

        self.wg1.submitters.add(self.editor)

        self.assertEqual(self.editor.profile.editable_workgroups.count(),1)
        self.item1 = self.itemType.objects.create(name="admin_page_test_oc",description=" ",workgroup=self.wg1,**self.create_defaults)
    def logout(self):
        self.client.post(reverse('django.contrib.auth.views.logout'), {})

    def login_editor(self):
        self.logout()
        response = self.client.post(reverse('friendly_login'), {'username': 'eddie', 'password': 'editor'})
        self.assertEqual(response.status_code,302)
        return response
    def assertResponseStatusCodeEqual(self,response,code):
        self.assertEqual(response.status_code, code)

    def test_bar(self):
        print("Do Bar")
        self.do_foo()
        print("Bar done")
    def test_foo(self):
        print("Do Foo")
        self.login_editor()
        response = self.client.get(reverse("admin:%s_%s_changelist"%(self.itemType._meta.app_label,self.itemType._meta.model_name)))
        self.assertResponseStatusCodeEqual(response,200)
        self.do_foo()
        print("Foo done")
    def test_zip(self):
        print("Do Zip")
        self.do_foo()
        print("Zip done")
    def do_foo(self):
        url_bits = (self.itemType._meta.app_label,self.itemType._meta.model_name)
        response = self.client.post(reverse('friendly_login'), {'username': 'eddie', 'password': 'editor'})

        response = self.client.get(reverse("admin:%s_%s_add"%url_bits))

        data = {'name':"admin_page_test_oc",'description':"test","workgroup":self.wg1.id,
                    'statuses-TOTAL_FORMS': 0, 'statuses-INITIAL_FORMS': 0 #no substatuses
                }
        response = self.client.post(reverse("admin:%s_%s_add"%url_bits),data)
        self.item1 = self.itemType.objects.first()
        response = self.client.get(reverse("admin:%s_%s_change"%url_bits,args=[self.item1.id]))

        data['name'] = "updated"
        # Re post the same data
        response = self.client.post(
                reverse("admin:%s_%s_change"%url_bits,args=[self.item1.id]),
                data
                )
        print response
        self.item1 = self.itemType.objects.first() # decache
        self.assertTrue(self.item1.name == "updated")
4

2 に答える 2

1

そのワークグループをロードする場所を移動することから始めます。ワークグループの作成をsetUpとの間で移動してみてくださいsetUpClass。これにより、TestCase 内のすべてのテストに対してワークグループをそのままにしておく効果があり、これはおそらくあなたが望むものです。

def setUp(self):
    from django.test import Client
    self.client = Client()

@classmethod
def setUpClass(cls):
    cls.wg1 = models.Workgroup.objects.create(name="Test WG 1") # Editor is member
    super().setUpClass() # Python 3 version

備品は一般的に悪夢ですが、これで問題が解決しない場合は、そのワークグループを備品に移動して問題が解決するかどうかを確認したいと思います。

于 2015-06-08T15:00:10.030 に答える
0

うわー、なんてワイルドでクレイジーな乗り物でしょう!!

RelatedListFilter問題を引き起こしていたカスタム クエリセットの問題であることが判明しました。この回答に対するコメントは、次のことを指摘しています。

フィルタ ルックアップが何らかの方法でキャッシュされています

field および field.rel オブジェクトはリクエスト間で保持されます

場合によっては、トランザクションのロールバックを超えてもそうです!

話のモラルListFilters、管理者で使うときは気をつけて!

于 2015-06-11T12:23:55.117 に答える