美文网首页
Unit Testing

Unit Testing

作者: Qingzh | 来源:发表于2015-04-08 11:47 被阅读0次

    Unit Test

    • What 什么是单元测试
    • Why 为什么要做单元测试
    • How 怎么做单元测试

    What is Unit Test

    • 什么是单元测试
    • 最小代码块,最基本功能
    • 最少依赖,可独立执行
    • 易于执行,可重现,可自动化
    • 什么不是单元测试:
    • 访问数据库
    • 访问网络(如 RESTful 服务接口)
    • 访问文件系统
    • 不能独立运行
    • 运行单元测试需要额外的配置等

    Why Unit Test

    • 可持续的替代手动测试
    • 保证基本功能达到预期
    • 减少可预期的bug
    • 有助于团队协作

    How to do Unit Test

    Python 单元测试 unittest:

    • test fixture 测试现场
    • test case 测试用例
    • test suite 测试集
    • test runner 测试执行
      • settings.TEST_RUNNER: django.test.simple.DjangoTestSuiteRunner

    What's a Test Case

    • Setup 建立测试现场
    • Action 执行
    • Assertion 断言
    • Teardown 清理测试现场

    What's a Test Case

    Django UnittestDjango Unittest

    Code

    <pre><code>
    def check_email_available(request):
    get_vars = request.GET
    js = {'success': False}
    if len(User.objects.filter(email=get_vars['email'])) > 0:
    js['value'] = _("An account with the Email '{email}' already exists.").format(
    email=get_vars['email'])
    js['field'] = 'email'
    return JsonResponse(js, status=200)
    js['success'] = True
    return JsonResponse(js, status=200)
    </code></pre>

    Unit Testing

    <pre><code>
    class CheckEmailTest(TestCase):
    def setUp(self):
    # Create the test client
    self.client = Client()
    self.url = reverse('student.views.check_email_available')

    def test_email_available(self):
        post_params = {'email': 'test8f9g@gmail.com'}
        with patch('student.models.AUDIT_LOG') as mock_audit_log:
            result = self.client.get(self.url, post_params)
        # Assertion: Check response and log
        self._assert_response(result, success=True)
    
    def test_email_unavailable(self):
        post_params = {'email': 'test8f9g@edx.org'}
        with patch('student.models.AUDIT_LOG') as mock_audit_log:
            result = self.client.get(self.url, post_params)
        # Assertion: Check response and log
        self._assert_response(result, success=False)
    

    </code></pre>


    <pre><code>
    class LoginAjaxTest(TestCase):
    def setUp(self):
    self.email = 'bryantly@126.com'
    self.client = Client()
    self.url = reverse('login')

    def test_login_success(self):
        post_params = {'email': self.email, 'password':'12345678'}
        with patch('student.models.AUDIT_LOG') as mock_log:
            result = self.client.post(self.url, post_params)
        self._assert_response(result, success=True)
    
    def test_login_failure_password_blank(self):
        post_params = {'email': self.email, 'password':''}
        with patch('student.models.AUDIT_LOG') as mock_log:
            result = self.client.post(self.url, post_params)
        expectedDict = {'issue':'blank', 'field':'password'}
        self._assert_response(result, success=False, **expectedDict)
    

    </code></pre>


    Unittest in Django

    1. 寻找django.test.TestCase的子类
    1. 建立用于测试的数据库
    2. 寻找以 test开头的方法
    3. 建立实例
    4. 检测结果

    Test Doubles

    1. Dummy Object: 需要传递但不会真正调用
    1. Fake Object: 是真正接口或抽象类的简易实现
    2. Test Stub: 传递间接的输入
    3. Mock Object: 记录间接的输出

    Why Mock

    • 真实对象的行为具有不确定性,例如网络延迟
    • 真实对象难以创建,例如和UI交互
    • 真实对象的行为难以模拟,例如网络错误
    • 真实对象运行效率很低,读写数据库等
    • 真实对象还没有实现

    Mock in Python

    Python mock 模块

    • MagicMock()
    • patch(), patch.object(), patch.dict()
      <pre><code>
      from StringIO import StringIO
      class classA(object):
      def get_value(self, x):
      # TODO: get value of x
      def foo(x):
      print '{}{}'.format(x, '>10' if classA().get_value(x) >10 else '<=10')
      </code></pre><pre><code>
      @patch('sys.stdout', new_callable=StringIO)
      @patch('main.classA', new_callable=MagicMock)
      def test_value_gt_10(mock_class, mock_stdout):
      mock_class.return_value.get_value.return_value = 11
      foo('fooCallable')
      assert mock_stdout.getvalue() == 'fooCallable>10\n'
      </code></pre><pre><code>
      @patch('sys.stdout', new_callable=StringIO)
      @patch('main.classA', new_callable=MagicMock)
      def test_value_lt_10(mock_class, mock_stdout):
      mock_class.return_value.get_value.return_value = 10
      foo('foo')
      assert mock_stdout.getvalue() == 'foo<=10\n'
      </code></pre>

    foo()函数:

    1. 获取classA().get_value(x)的返回值
    1. 当返回值>10,打印x+'>10'到标准输出
    2. 当返回值<=10,打印x+'<=10'到标准输出

    哪些需要mock:

    1. 标准输出('sys.stdout')
      用 'StringIO' 假扮 'sys.stdout' 获取间接输出:
      @patch('sys.stdout', new_callable=StringIO)
    1. 间接输入 classA.get_value(x)
      用 'MagicMock' 假扮 '__main__.classA' 传递间接输入:
      Mock classA:
      @patch('__main__.classA', new_callable=MagicMock)
      Mock classA().get_value():
      mock_class.return_value.get_value.return_value = 30

    UnitTest in Edx

    • Factory 的修改
    • TestCase 的更新
    • 自动化配置

    相关阅读

    edx 测试概要

    相关文章

      网友评论

          本文标题:Unit Testing

          本文链接:https://www.haomeiwen.com/subject/xfhzxttx.html