Django unit testing problems encountered

Unit testing framework unittest

python unittest is carrying a unit testing framework, without having to install, easy to use.

unittest in the core part is: TestFixture, TestCase, TestSuite, TestRunner

unittest case of running processes:

  1. A complete written TestCase
  2. A plurality TestCase TestSuite TestLoder is loaded into the inside, can also be nested TestSuite TestSuite
  3. The results from the TextTestRunner to perform TestSuite, test saved in the TextTestResult
  4. TestFixture refers to the preparation and recovery environment

TestFixture

Prepare for the test environment and reducing recovery, generally used in the following several functions:

  1. Run before each test case run:) (setUp
  2. tearDown (): executed after completion of each test case run
  3. setUpClass (): You must use @classmethod decorator run only once before all run case
  4. tearDownClass (): You must use @classmethod decorator, runs only run once after the completion of all case

TestCase

  • The results: 成功是 .failure is F, the error is E, S is skipped
  • The order of execution of test cases with the method does not matter, in alphabetical order by default
  • Each test methods are test 开头

Test model file:

# -*- coding: utf-8 -*-
import unittest


class TestMy(unittest.TestCase):
    def setUp(self):
        # 每个测试用例运行之前执行
        print 'setUp'

    def tearDown(self):
        # 每个测试用例运行之后执行
        print 'tearDown'

    @classmethod
    def setUpClass(cls):
        # 所有测试用例运行之前执行
        print 'setUpClass'

    @classmethod
    def tearDownClass(cls):
        # 所有测试用例运行之后执行
        print 'tearDownClass'

    def run_test(self):
        # 不是以test开头,不是测试用例
        print 'run'

    def test_run_a(self):
        # 测试用例
        self.assertEqual(1, 1)

    def test_run_b(self):
        # 测试用例
        self.assertEqual(1, 2)

After the unit tests run to completion, success will print a ".", Will show the assertion failure of local failure.

Django unit testing

django unit based on the test module is written unittest. We use class named django.test.TestCase, inherited from the python unittest.TestCase. So it's the whole process is entirely consistent with unittest.

  • Different points: the Client class is defined for analog transmission request more in the test project Django.test module.
from django.test import TestCase
import json

class TestAlarm(TestCase):

      def test_nic_type(self):
        # 测试获取NIC类型接口
        r = self.client.get('/api/home/nic_type/')
        self.assertEqual(r.status_code, 200)

        content = json.loads(r.content)
        self.assertEqual(content['result'], True)


Django support request type

Request type Call the method
Post request post(path, data=None, content_type=MULTIPART_CONTENT, follow=False, secure=False, **extra)
Get request get(path, data=None, follow=False, secure=False, **extra)
Put request put(path, data='', content_type='application/octet-stream', follow=False, secure=False, **extra)
Patch Request patch(path, data='', content_type='application/octet-stream', follow=False, secure=False, **extra)
Delete request delete(path, data='', content_type='application/octet-stream', follow=False, secure=False, **extra)

Common Definition:

parameter name Meaning Explanation
path Send a request using the url
data When a data transmission request carrying
content_type Carrying the format of the data
secure The client HTTPS request analog
follow The client will follow any redirects

Wherein: post, put, patch, delete request when the application process is content_type JSON, if data is dict, list or tuple type, is required json.dumps () to serialize /.

Receiving and processing the request data

Client request issued by the object after a series of operations of the test unit, the data is returned to the return value returned in the form. In general, data is returned in the form of a rear end json格式, after receiving the data call needs to json方法be resolved.

import json

 def test_nic_type(self):
       # 测试获取NIC类型接口
       response = self.client.get('/api/home/nic_type/')
       self.assertEqual(response.status_code, 200)
       content = json.loads(response.content)

Which, response of common attributes are:

  • status_code: http status codes
  • content: reponse of the body, json format, when analyzed by way json

Results show

  • self.assertEqual(1, 2): 断言1==2
  • self.assertTrue (isinstance (content, list)): assert that the content type is a list
  • self.assertContains (response, text, count = None, status_code = 200, msg_prefix = '', html = False): whether the corresponding response to the assertion status_code text and content. True will set the html text as html treatment.
  • self.assertJSONEqual (raw, expected_data, msg = None): Json fragments and asserts quite raw and expected_data.

mock data

mock auxiliary unit test module for testing is not convenient to call someone else's interface.

use:

In the python2.x, the mock is a separate module, use need to install

pip install mock

After python3.3, mock unittest been incorporated into a module, a unit testing unittest part, come directly into the line

from unittest import mock

Example of use

We need to test methods:

    def get_os_account(cls, bk_biz_id):
        params = {
            'bk_biz_id': bk_biz_id
        }
        accounts = JobApi.get_os_account(params=params)
        return accounts

Wherein when JobApi.get_os_account not call for the external interface unit tests, it is necessary to use mock data using the following method:

import mock

def test_get_os_account(self):
    """
    测试方法get_os_account
    :return:
    """
    JobApi.get_os_account = mock.MagicMock(return_value=Mock_Os)
    data = Rules.get_os_account(
        bk_biz_id=2
    )
    self.assertTrue(isinstance(data, dict))

Mock_Os which is:

Mock_Os = {
    "result": True,
    "code": 0,
    "message": "success",
    "data": [
        {
            "id": 2,
            "account": "Administrator",
            "creator": "system",
            "os": "Windows",
            "alias": "Administrator",
            "bk_biz_id": 2,
            "create_time": "2018-03-22 15:36:31"
        }
    ]
}

database

Testing is required databases, django will generate a separate database for testing. Regardless of whether your tests passed, after all when you perform the test, the test database is destroyed.

  • Points to note: during the execution of unit tests, Django will generate a temporary database, so users need to have a connection to the database to create and delete rights to the database.
  • By default, the name of the test database is test_DATABASE_NAME, DATABASE_NAME is the name of the database you configured in settings.py years;
  • If you need to test a database other names can be specified TEST_DATABASE_NAME values ​​in settings.py

Configure the test database, increase TEST field in setting.py file DATABASES

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',  # 默认用mysql
        'NAME': 'hn_collector',                        # 数据库名 (默认与APP_ID相同)
        'USER': 'root',                        # 你的数据库user
        'PASSWORD': '123456',                    # 你的数据库password
        'HOST': '127.0.0.1',                   # 开发的时候,使用localhost
        'PORT': '3306',                        # 默认3306
        'TEST': {
            'NAME': 'data_collector_test',
            'CHARSET': 'utf8',
            'COLLATION': 'utf8_general_ci'
        },
        'OPTIONS': {'charset': 'utf8'},
    },
}

Recommended configuration database, you can modify the configuration of the test database. Otherwise it will be easier to go wrong: encoding issues such as: Chinese can not be put in storage, etc.

keepdb

When writing unit tests, each time re-create the MySQL database tables takes a long time, so in the case of the results of the same table, want to use the parameter keepdb

python manage.py test --keepdb

Test Data: fixtures

Some projects are based on database development, if the database has no data, then for a database-based web sites, test case not much use. In order to join the test data to the test database is more convenient, django provides load fixtures Methods.

fixture is a series of data sets, django know how to import it into the database.

Steps for usage
  • Fixtures create a folder in myapp, create a file in the folder myapp.json
  • Json configuration file
[{
    "fields": {
        "subnets": "1",
        "update_time": "2020-03-13T16:48:15",
        "name": "test",
        "ch_operator": null,
        "scan_time": "2020-03-13T18:31:30",
        "edit_user": null,
        "is_delete": 0,
        "create_user": "wangying",
        "create_time": "2020-03-13T16:48:15"
    },
    "model": "tasks.tasksconfig",
    "pk": 3
}, {
    "fields": {
        "status": 1,
        "edit_time": "2020-03-13T16:48:15",
        "is_delete": 0,
        "create_user": "wangying",
        "create_time": "2020-03-13T16:48:15",
        "frequency": 60,
        "time": "02:00:00",
        "day": 5,
        "tasksconfig": 3
    },
    "model": "tasks.cycle",
    "pk": 3
}]

  • If there is actual data in the database, the data may be copied directly to the myapp.json file copy command follows
python manage.py dumpdata myapp >myapp/fixtures/myapp.json
  • setting.py added: FIXTURE_DIRS = ( '/ path / to / api / fixtures /',)
  • Use the test file:
class TestHome(BaseTestCase):
    fixtures = ['ip_address.json']

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

Login authentication

Directly to the login authentication mock out, the middleware can bypass authentication (not recommended)

@patch('account.middlewares.LoginMiddleware',return_value={'user': 'wy'})
    def test_all_sub(self, user):

Direct cookie assignment

    def setUp(self):
        self.client.cookies['bk_token'] = 'bk_token'

Celery unit testing

Unit testing asynchronous tasks

A simple example:

@task()
def add():
    print '33333'
    def task_celery(self, request):
        type = request.GET.get('type')
        if int(type) == 1:
            add.delay()
            data = {
                'status': 1
            }
        else:
            data = {
               'status': 2
            }
        return Response(data)

Unit Test Method: Use CELERY_ALWAYS_EAGER = True

  • Decorator override_settings
from django.test.utils import override_settings

    @override_settings(CELERY_ALWAYS_EAGER=True)
    def test_add(self):
        param = {
            'type': 1
        }
        r = self.client.get('/api/task/task_celery/', param, content_type='application/json')
        self.assertEqual(r.status_code, 200)

        content = json.loads(r.content)
        self.assertEqual(content['result'], True)
  • Directly modify settings
from django.conf import settings

    def setUp(self):
        settings.CELERY_ALWAYS_EAGER = True

If set CELERY_ALWAYS_EAGER=True, the following two lines of code no difference

add.delay()
add()

File Upload:

Simply provide the file name as the key field, and provide a file to upload a file handle as the value.

    def test_upload_file(self):
        """
        测试方法 upload_file
        :return:
        """
        with open('apps/test_handlers/mock_data/upload_file/ydauto_tomcat.zip') as fb:
            r = self.client.post('/api/scripts/', data={'file': fb})
            content = json.loads(r.content)
            self.assertEqual(r.status_code, 200)

file is just a key, you can define your own

Running unit tests

  • Test the entire projectpython manage.py test
  • Testing an applicationpython manage.py test app_name
  • Test only a Casepython manage.py test MyTestCase
  • Only one test methodpython manage.py test test_func

Test by:

Guess you like

Origin www.cnblogs.com/wangyingblock/p/12478512.html