Python中Mock的示例

   <h3>一些常用的mock示例</h3>    <p>先简单定义个类,方便举例:</p>    <pre>  <code class="language-python">class Person:      def__init__(self):          self.__age = 10                defget_fullname(self, first_name, last_name):          return first_name + ' ' + last_name                defget_age(self):          return self.__age                @staticmethod      defget_class_name():          return Person.__name__  </code></pre>    <p>这个类里有两个成员方法,一个有参数,一个无参数。还有一个静态方法</p>    <p>mock成员方法</p>    <p>1. 使用Mock类,返回固定值</p>    <pre>  <code class="language-python">class PersonTest(TestCase):      deftest_should_get_age(self):          p = Person()                    # 不mock时,get_age应该返回10          self.assertEqual(p.get_age(), 10)                    # mock掉get_age方法,让它返回20          p.get_age = Mock(return_value=20)          self.assertEqual(p.get_age(), 20)            deftest_should_get_fullname(self):          p = Person()                    # mock掉get_fullname,让它返回'James Harden'          p.get_fullname = Mock(return_value='James Harden')          self.assertEqual(p.get_fullname(), 'James Harden')  </code></pre>    <p>2. 校验参数个数,再返回固定值</p>    <p>上面的例子你也许已经注意到了,调用p.get_fullname时没有给任何的参数,但是依然可以工作。</p>    <p>如果想校验参数需要用 <strong>create_autospec</strong> 模块方法替代Mock类。</p>    <pre>  <code class="language-python">class PersonTest(TestCase):      deftest_should_get_fullname(self):          p = Person()                    p.get_fullname = create_autospec(p.get_fullname, return_value='James Harden')                    # 随便给两个参数,依然会返回mock的值          self.assertEqual(p.get_fullname('1', '2'), 'James Harden')                     # 如果参数个数不对,会报错TypeError: missing a required argument: 'last_name'          p.get_fullname('1')  </code></pre>    <p>3. 使用side_effect, 依次返回指定值</p>    <pre>  <code class="language-python">class PersonTest(TestCase):      deftest_should_get_age(self):          p = Person()                    p.get_age = Mock(side_effect=[10, 11, 12])             self.assertEqual(p.get_age(), 10)          self.assertEqual(p.get_age(), 11)          self.assertEqual(p.get_age(), 12)  </code></pre>    <p>4. 根据参数不同,返回不同的值</p>    <pre>  <code class="language-python">class PersonTest(TestCase):      deftest_should_get_fullname(self):          p = Person()                    values = {('James', 'Harden'): 'James Harden', ('Tracy', 'Grady'): 'Tracy Grady'}          p.get_fullname = Mock(side_effect=lambda x, y: values[(x, y)])                    self.assertEqual(p.get_fullname('James', 'Harden'), 'James Harden')          self.assertEqual(p.get_fullname('Tracy', 'Grady'), 'Tracy Grady')  </code></pre>    <p>5. 抛出异常</p>    <pre>  <code class="language-python">class PersonTest(TestCase):      deftest_should_raise_exception(self):          p = Person()                    p.get_age = Mock(side_effect=TypeError('integer type'))          # 只要调就会抛出异常          self.assertRaises(TypeError, p.get_age)  </code></pre>    <p>6. 检验是否调用</p>    <pre>  <code class="language-python">class PersonTest(TestCase):      deftest_should_validate_method_calling(self):          p.get_fullname = Mock(return_value='James Harden')             # 没调用过          p.get_fullname.assert_not_called()  # Python 3.5             p.get_fullname('1', '2')             # 调用过任意次数          p.get_fullname.assert_called() # Python 3.6          # 只调用过一次, 不管参数          p.get_fullname.assert_called_once() # Python 3.6          # 只调用过一次,并且符合指定的参数          p.get_fullname.assert_called_once_with('1', '2')             p.get_fullname('3', '4')          # 只要调用过即可,必须指定参数          p.get_fullname.assert_any_call('1', '2')             # 重置mock,重置之后相当于没有调用过          p.get_fullname.reset_mock()          p.get_fullname.assert_not_called()                    # Mock对象里除了return_value, side_effect属性外,          # called表示是否调用过,call_count可以返回调用的次数          self.assertEqual(p.get_fullname.called, False)          self.assertEqual(p.get_fullname.call_count, 0)                    p.get_fullname('1', '2')          p.get_fullname('3', '4')          self.assertEqual(p.get_fullname.called, True)          self.assertEqual(p.get_fullname.call_count, 2)  </code></pre>    <p>mock静态方法</p>    <p>静态方法和模块方法需要使用 <strong>patch</strong> 来mock。</p>    <p>1. 在测试方法参数中得到Mock对象</p>    <pre>  <code class="language-python">class PersonTest(TestCase):      # 以字符串的形式列出静态方法的路径,在测试的参数里会自动得到一个Mock对象      @patch('your.package.module.Person.get_class_name')      deftest_should_get_class_name(self, mock_get_class_name):          mock_get_class_name.return_value = 'Guy'             self.assertEqual(Person.get_class_name(), 'Guy')  </code></pre>    <p>2. 在patch中设置Mock对象</p>    <pre>  <code class="language-python">class PersonTest(TestCase):      mock_get_class_name = Mock(return_value='Guy')         # 在patch中给出定义好的Mock的对象,好处是定义好的对象可以复用      @patch('your.package.module.Person.get_class_name', mock_get_class_name)      deftest_should_get_class_name(self):          self.assertEqual(Person.get_class_name(), 'Guy')  </code></pre>    <p>3. 使用patch.object</p>    <pre>  <code class="language-python">class PersonTest(TestCase):      mock_get_class_name = Mock(return_value='Guy')         # 使用patch.object来mock,好处是Person类不是以字符串形式给出的      @patch.object(Person, 'get_class_name', mock_get_class_name)      deftest_should_get_class_name(self, ):          self.assertEqual(Person.get_class_name(), 'Guy')  </code></pre>    <p>4. 使用with控制作用域</p>    <pre>  <code class="language-python">class PersonTest(TestCase):      # 作用域之外,依然返回真实值      deftest_should_get_class_name(self, ):          mock_get_class_name = Mock(return_value='Guy')          withpatch('your.package.module.Person.get_class_name', mock_get_class_name):              self.assertEqual(Person.get_class_name(), 'Guy')             self.assertEqual(Person.get_class_name(), 'Person')  </code></pre>    <p>mock链式调用</p>    <p>在django里,我们经常需要mock数据库,而访问数据库时经常是链式调用,看个例子。</p>    <pre>  <code class="language-python">defget_person(name):      return Person.objects.filter(name=name).order_by('age')  </code></pre>    <p>有个模块方法,返回数据库中所有指定name的人员,并按age排序</p>    <p>mock掉整个数据库访问</p>    <pre>  <code class="language-python">@patch('your.package.module.Person.objects.filter')  deftest_should_get_person(self, mock_filter):      # 先得到一个filter的Mock对象,再在return_value中设置一个Mock对象,此时不需要自己再创建      mock_filter.return_value.order_by.return_value = None            self.assertIsNone(get_person())  </code></pre>    <p> </p>    <p>来自:http://python.jobbole.com/87656/</p>    <p> </p>