2017-06-29 11 views
7

django-cacheopsを使用して、自分のビューがキャッシュされることをテストしたいと思います。私のテストケースでは、ヒットまたはミスのためにキャッシュ内の値をインクリメントする必要があるハンドラにcacheop cache_readシグナルを接続しています。しかし、信号は決して発射されません。誰かが純粋にそのテストケースで使用するために、テストケースでDjangoシグナルハンドラを接続する正しい方法を知っていますか?テストでdjangoシグナルハンドラを接続する

は、ここでは私も同じ結果をすべて、モジュールレベルで、かつ定期的なテストケースsetUp方法でシグナルハンドラを接続しようとしたこれまでのところ、私が持っているもの

from cacheops.signals import cache_read 

cache.set('test_cache_hits', 0) 
cache.set('test_cache_misses', 0) 

def cache_log(sender, func, hit, **kwargs): 
    # never called 
    if hit: 
     cache.incr('test_cache_hits') 
    else: 
     cache.incr('test_cache_misses') 


class BootstrapTests(TestCase): 

    @classmethod 
    def setUpClass(cls): 
     super(BootstrapTests, cls).setUpClass() 
     cache_read.connect(cache_log) 
     assert cache_read.has_listeners() 

    def test_something_that_should_fill_and_retrieve_cache(self): 
     .... 
     hits = cache.get('test_cache_hits') # always 0 

です。

EDIT: ここに私の実際のテストコードとテストしているオブジェクトがあります。私はcached_asデコレータを使って関数をキャッシュしています。このテストは現在失敗しています。

boostrap.py

class BootstrapData(object): 

    def __init__(self, app, person=None): 
     self.app = app 

    def get_homepage_dict(self, context={}): 

     url_name = self.app.url_name 

     @cached_as(App.objects.filter(url_name=url_name), extra=context) 
     def _get_homepage_dict(): 
      if self.app.homepage is None: 
       return None 

      concrete_module_class = MODULE_MAPPING[self.app.homepage.type] 
      serializer_class_name = f'{concrete_module_class.__name__}Serializer' 
      serializer_class = getattr(api.serializers, serializer_class_name) 
      concrete_module = concrete_module_class.objects.get(module=self.app.homepage) 
      serializer = serializer_class(context=context) 
      key = concrete_module_class.__name__ 
      return { 
       key: serializer.to_representation(instance=concrete_module) 
      } 
     return _get_homepage_dict() 

test_bootstrap.py

class BootstrapDataTest(TestCase): 

    def setUp(self): 
     super(BootstrapDataTest, self).setUp() 

     def set_signal(signal=None, **kwargs): 
      self.signal_calls.append(kwargs) 
     self.signal_calls = [] 
     cache_read.connect(set_signal, dispatch_uid=1, weak=False) 
     self.app = self.setup_basic_app() # creates an 'App' model and saves it 

    def tearDown(self): 
     cache_read.disconnect(dispatch_uid=1) 

    def test_boostrap_data_is_cached(self): 

     obj = BootstrapData(self.app) 
     obj.get_homepage_dict() 

     # fails, self.signal_calls == [] 
     self.assertEqual(self.signal_calls, [{'sender': App, 'func': None, 'hit': False }]) 

     self.signal_calls = [] 

     obj.get_homepage_dict() 
     self.assertEqual(self.signal_calls, [{'sender': App, 'func': None, 'hit': True}]) 
+1

テストで 'cache_read'シグナルが発生することは確かですか?キャッシュの読み込みだけではなく、cacheopsの 'cache_read'信号がトリガーされます。 https://github.com/Suor/django-cacheops/blob/master/cacheops/query.py また、cachopsパッケージには、 'setUp'メソッドで信号を接続するテストの例があります。 https://github.com/Suor/django-cacheops/blob/daa907d6ec5dc98d5cc80a3d519469fb134bd0bb/tests/tests.py#L917 – ARJMP

+1

私は間違っているかもしれませんが、django-cacheopsは通常のキーではなくクエリーセットをキャッシュするように設計されています。したがって、取得しようとしている値がクエリーセットではないので、 'cache_read'シグナルは呼び出されません。 – mattjegan

+0

あなたはおそらくcacheops要求を出したり、ヒットを得ることはありません。テストコードを提供する必要があります。 – Suor

答えて

0

このケースでは、私のテストケースがdjangoのRestartフレームワークのAPITestCaseをサブクラス化し、djangoのSimpleTestCaseをサブクラス化していることが判明しました。

cacheopsソースを調べてみると、これらのテストはTransactionTestCaseのサブクラスであり、テストケースを切り替えるとこの問題が解決されています。

これがなぜそのようなのか知りたいのですが、問題は今解決されています。

+0

これは、 'SimpleTestCase'が各テストをトランザクションにラップし、キャッシュトップが一度汚れてしまったトランザクションで自身をオフにするためです。これは、トランザクション内から見えるdb状態が異なり、キャッシュに入れたり、キャッシュに頼ったりしないでください。 – Suor

+0

ああ、説明をありがとう – bharling

1

私はなぜこれが起こっている見ることができませんが、私はとにかく便利な答えをしようとします。

最初に、キャッシュが機能するかどうかをテストしたい場合は、それを確認するために独自の副作用に頼るべきではなく、シグナルは主な機能の副作用である--dbコールを防止します。それをテストしてみてください。

def test_it_works(self): 
    with self.assertNumQueries(1): 
     obj.get_homepage_dict() 

    with self.assertNumQueries(0): 
     obj.get_homepage_dict() 

第二に、あなたはあなたに何が起こっているのかを知りたい場合はcacheopsコードを含むどこでもプリントを追加することで掘ると、それが停止した場所を見ることができます。また、あなたは私のためのテストを行うことができます、指示はここにhttps://github.com/Suor/django-cacheops#writing-a-testです。

最後に、あなたのテストは少し間違っています。 @cached_as()の場合、送信者はNoneとなり、funcは装飾機能となります。

+0

助けてくれてありがとう - この数ヶ月後に私は、テストケースがTransactionTestCaseをベースとして使用しなかったことが原因であることを知りました。テストケースの基本クラスを切り替えることで、すべての作業が完了します。 – bharling

関連する問題