如何使用Python为Django的赛车条件编写单元测试?

时间:2019-04-25 06:29:40

标签: python django unit-testing testing race-condition

我已经实现了一个基于Django和Django REST框架的API,发现在高度并发的情况下工作时会遇到一些问题。

因此,我有兴趣编写一些测试代码以重现该问题,并改进代码以使其稍后能够安全地线程化。

我已经尝试过before_after库,如果代码的繁忙部分不是函数或者是函数但包含参数,则很难使用。

我也尝试过使用ThreadPoolExecutor来生成赛车条件,但是会引发django.db.utils.DatabaseError: DatabaseWrapper objects created in a thread can only be used in that same thread. The object with alias 'default' was created in thread id 4328317000 and this is thread id 4690485864.

我的实现是这样的:

class TestOrderViewSet(APILiveServerTestCase, AuthRequestMixin):

    def test_replace_order_thread_safety(self):
        john_balance = self.john.wallet.balance
        jane_balance = self.jane.wallet.balance
        order_user_pairs = [(mommy.make_recipe('payments.tests.jane_order'), self.jane)]
        for i in range(10):
            order_user_pairs.append((mommy.make_recipe('payments.tests.jane_order'), self.jane))
            order_user_pairs.append((mommy.make_recipe('payments.tests.john_order'), self.john))
        random.shuffle(order_user_pairs)
        print(order_user_pairs)
        self.assertGreaterEqual(Order.objects.count(), 20)

        def replace_order(order, user, i):
            print(i, order.id)
            response = self.auth_post('order', {'pk': order.id}, user)
            print(i, user.wallet.balance)
            self.assertEqual(response.status_code, 200)
            user.wallet.refresh_from_db()
            print(i, user.wallet.balance)

        def count_done():
            return sum(int(r.done()) for r in results)

        with ThreadPoolExecutor(max_workers=4) as e:
            results = []
            for i in range(10):
                r = e.submit(replace_order, *order_user_pairs[i], i)
                results.append(r)
                r = e.submit(replace_order, *order_user_pairs[i], i)
                results.append(r)

            print('done', count_done())
        # e.shutdown(wait=True)
        print('done', count_done())

        self.john.wallet.refresh_from_db()
        self.jane.wallet.refresh_from_db()
        self.assertEqual(self.john.wallet.balance, john_balance + 1)
        self.assertEqual(self.jane.wallet.balance, jane_balance - 1)

任何建议都值得赞赏。预先感谢。

0 个答案:

没有答案