2017-11-10 2 views
3

は基本的に、私は10回以上のためにこれを行う必要があり、私は複数のモデルのために類似したURLのためにDjangoのビューのための同様のテストケースを書くより速い方法がありますか?

from django.test import RequestFactory, TestCase 
class BaseApiTest(TestCase): 
def setUp(self): 
    superuser = User.objects.create_superuser('test', '[email protected]', 'testpassword') 
    self.factory = RequestFactory() 
    self.user = superuser 
    self.client.login(username=superuser.username, password='testpassword') 

class SomeModelApiTests(base_tests.BaseApiTest): 
def test_update_with_only_1_field(self): 
    """ 
    Tests for update only 1 field 

    GIVEN the following shape and related are valid 
    WHEN we update only with just 1 field 
    THEN we expect the update to be successful 
    """ 
    shape_data = { 
     'name': 'test shape', 
     'name_en': 'test shape en', 
     'name_zh_hans': 'test shape zh hans', 
     'serial_number': 'test shape serial number', 
     'model_name': { 
      'some_field': '123' 
     } 
    } 

    data = json.dumps(shape_data) 
    response = self.client.post(reverse('shape-list-create'), data, 'application/json') 
    self.assertEqual(response.status_code, status.HTTP_201_CREATED) 

    some_model = response.data['some_model'] 
    new_some_field = '12345' 

    data = json.dumps({'some_field': new_some_field, 'id': response.data['some_model']['id']}) 
    response = self.client.put(reverse('some-model', args=[some_model['id']]), data, 'application/json') 
    self.assertEqual(response.status_code, status.HTTP_200_OK) 
    self.assertEqual(new_some_field, response.data['some_field']) 

を同じテストケース(test_update_with_only_1_fieldを)書いていることを実感します。私はすでにそれをしています。

唯一の違いたびに、これを行うためのより高速な方法があります場合、私は思っていた次の句「some_model」、「いくつかのモデル」、および「some_field」

です。

私は抽象的に二つの方法を考えることができます:

  1. は何とか私は、コピー&ペースト、最終的なテストケースを生成することができ、テキストエディタでテンプレートを作成します。私は崇高なテキストを使用していますが、別のテキストエディタに切り替えても構いません。

  2. このテストケースを、個々のテストクラスが呼び出せるビヘイビアクラスに変換するという形で少し書くことができます。別名構成。

どちらが理にかなっていますか、これを行う方法は異なりますか?

BaseApiクラスもでない他のテストクラスに継承されていることに注意してください。には繰り返しテストケースメソッドがあります。

答えて

2

"some_model"のリスト/辞書をテスト用に作成し、 "some_model"アイテムごとにsubtesthttps://docs.python.org/3/library/unittest.html#distinguishing-test-iterations-using-subtests)を使用できます。

my_list_of_model = [FirstModel, SecondModel] 

for my_model in my_list_of_model: 
    with subTest(model=mymodel): 
     # Testing model here 

あなたはモデルごとに異なるTestCaseをしたい場合は、私は多重継承が進むべき道だと思います:

class BaseApiTestCase(TestCase): 
    def setUp(): 
     # Setup stuff 

class RepetitiveTestCaseMixin: 
    # Class to do the repetitive stuff 
    def test_update_should_work(self): 
     # Do some thing with self.model and self.field here 

class ModelTestCase(BaseApiTestCase, RepetitiveTestCaseMixin): 
    @classmethod 
    def setUpClass(cls): 
     super().setUpClass() 

     cls.model = MyModel 
     cls.field = 'some_field' 
+0

申し訳ありませんが私はペタニックだと思っていますが、構成よりも複数の継承の方があなたの2番目のソリューションではありませんか? –

+0

実際、baseapiクラスは、繰り返しテストケースを持たない他のモデルテストクラスに継承されています。どのようにして2番目の解決策が変わるでしょうか? –

+1

それは本当に複数の継承です、私は私の答えを編集しました。 2番目のコメントに答えるには、 'test_update_should_work'と他の共有メソッドを' BaseApiTestCase'ではなくmixinで動かすだけです。そうすればModelTestCaseは 'class ModelTestCase(BaseTestCase、RepetitiveTestCaseMixin)'のようになります... だからあなたは 'RepetitiveTestCaseMixin'を継承するかどうかを選択する必要があります(私の答えをこのように編集しました) –

4

私はあなたが何をしたいと思いますが、「パラメータ化テスト」、標準unittestです

import unittest 
from parameterized import parameterized 

class SomeModelApiTests(unittest.TestCase): 

    @parameterized.expand([ 
     ('case1', 'm1', 'f1', 'nf1'), 
     ('case1', 'm2', 'f2', 'nf2'), 
    ]) 
    def test_update_with_only_1_field(self, dummy_subtest_name, model_name, field_name, new_field_value): 
     print(model_name, field_name, new_field_value) 

ます利回り:

パッケージでこれを行うことができます
test_update_with_only_1_field_0_case1 (t.SomeModelApiTests) ... m1 f1 nf1 
ok 
test_update_with_only_1_field_1_case1 (t.SomeModelApiTests) ... m2 f2 nf2 
ok 

pytestテストフレームワークは、parameterized testsの組み込みの方が優れています。

2

私はテストを繰り返す必要があるときにmixin + "カスタマイズフック"を使うことがあります。質問の

例(及び「形状リスト作成」のようなエンドポイントは/リファクタリングを変更することがあり):

どうカスタマイズフックを分割する
class TestUpdateWithOnly1FieldMixin(object): 
    some_model = None 
    some_field = None 
    some_model2 = None 

    def get_some_model(self): 
     return self.some_model 

    def get_some_field(self): 
     return self.some_field 

    def get_some_model2(self): 
     return self.some_model2 

    def test_update_with_only_1_field(self): 
     some_model = self.get_some_model() 
     # represents some-model in example 
     some_model2 = self.get_some_model2() 
     some_field = self.get_some_field() 

     shape_data = { 
      'name': 'test shape', 
      'name_en': 'test shape en', 
      'name_zh_hans': 'test shape zh hans', 
      'serial_number': 'test shape serial number', 
      'model_name': { 
       some_field: '123' 
      } 
     } 

     data = json.dumps(shape_data) 
     response = self.client.post(reverse('shape-list-create'), data, 'application/json') 
     self.assertEqual(response.status_code, status.HTTP_201_CREATED) 

     some_model_data = response.data[some_model] 



class SomeModelApiTests(base_tests.BaseApiTest, TestUpdateWithOnly1FieldMixin): 
    some_model = 'choose your model' 
    some_field = 'some_field' 
    some_model2 = 'some-model' 

    def get_some_field(self): 
     # Do customization 
     return 'some-field after customize' 

、どのようなミックスインなどに置くために基づいています状況。 私の意見では、実際のテストケースを簡単に理解できるようにすることが目標です。(たぶん、 "ポストシェイプリスト作成"を別の関数に移動して、そのテストケースと実際には関連しないかもしれない)

もう1つの例は、カスタマイズを少しオーバーボードしています。

class TestWithGoodNameMixin(object): 
    some_model = None 
    some_field = None 

    # "Customization hooks" 

    def get_shape_data(self): 
     return {self.some_field: 'x'} 

    def create_model(self, shape_data): 
     response = self.client.post(reverse('shape-list-create'), shape_data, 
            'application/json') 
     self.assertEqual(response.status_code, status.HTTP_201_CREATED) 
     return response[self.some_model] 

    def create_put_data(self, some_model_data): 
     # Add default implementation 
     pass 

    # ..... 

    def test_update_with_only_1_field(self): 
     shape_data = self.get_shape_data() 
     some_model_data = self.create_model(shape_data) 

     data = self.create_put_data(some_model_data) 
     response = self.put_data(data) 

     self.assert_put_response(response) 
0

あなたはユニットテストのためにpytestパッケージを使用することができます。 非常に簡単で使いやすいです。

@pytest.mark.parametrize()デコレータを使用してその機能を実現できます。次のようにパラメータ化テストケースのため

例は次のとおりです。

import pytest 
class SampleTesting(object): 
    data_for_test = [ 
         ('{inputdata1:value1}','output1'), 
         ('{inputdata1:value2}','output2') 
        ] 
    @pytest.mark.parametrized('input_data, expected_output', data_for_test) 
    def test_sample_function(self, input_data, expected_output): 
     response = function_to_be_tested(input_data) 
     assert response == expected_output 

あなたはdocsにこのデコレータについての詳細を読むことができる「

また、セットアップにテスト機能を@pytest.fixture()デコレータを使用することができます。

関連する問題