模拟退火python实现_在Python单元测试中实现模拟的3种方法

模拟退火python实现

For code to be considered complete and reliable, more often than not people will ask “How do you know the function works as expected?” or “Have you tried to break your own code?”. Either question, it’s clear that unit testing is salient to being confident that your program will execute successfully. The last thing that you want to do is finish writing a program and be stuck fixing code that does not do what it’s suppose to.

为了使代码被认为是完整和可靠的,人们经常会问“您如何知道该功能按预期工作?” 或“您是否尝试破坏自己的代码?”。 不管是哪个问题,很明显,单元测试对于确保程序将成功执行至关重要。 您要做的最后一件事是完成程序编写,并被困在无法执行应有的功能的代码上。

By the end of this article, you will have an good understanding about what mock objects are and the different ways to mock objects or patch external libraries using Python’s unittest library.

到本文结尾,您将对什么是模拟对象以及使用Python的unittest库模拟对象或修补外部库的不同方法有一个很好的了解。

什么是单元测试? (What is Unit Testing?)

Unit testing is a branch of software testing that assesses if individual blocks of code (called units) can correctly execute to produce an expected result, independent of one another. Unit testing uses the white box testing methodology (or transparent box testing) where the tester has knowledge of the underlying structure of the unit being tested. With this in mind, the tester should only unit test their own code to have confidence in the program.

单元测试是软件测试的一个分支,它评估各个代码块(称为单元)是否可以正确执行以产生彼此独立的预期结果。 单元测试使用白盒测试方法(或透明盒测试),其中测试人员了解被测试单元的基础结构。 考虑到这一点,测试人员应该只对自己的代码进行单元测试以对程序充满信心。

Effective unit tests should also check that the function can handle erroneous data if a wrong input is passed. This is a fundamental step to a robust program, because you will most likely find weird and wonderful data inputs if uncleaned.

有效的单元测试还应该检查,如果传递了错误的输入,则该函数可以处理错误的数据。 这是程序健壮的基本步骤,因为如果不清理,您很可能会发现奇怪而奇妙的数据输入。

什么是模拟? (What is the Mock?)

As defined in the python unittest documentation…

如python unittest文档中所定义……

mock is a library for testing in Python. It allows you to replace parts of your system under test with mock objects and make assertions about how they have been used.

模拟 是用于在Python中进行测试的库。 它允许您用模拟对象替换被测系统的各个部分,并断言它们的使用方式。

A mock object will allow you to control a component of your program. For example, suppose you have program A that retrieves data from system A, from a unit testing perspective, your test should not dependent on system A working correctly. Rather, your test should check your program attempts to make a data request call to the system and return some data.

模拟对象将允许您控制程序的组件。 例如,假设您有程序A系统A检索数据从单元测试的角度来看,您的测试不应依赖于系统A正常工作。 相反,您的测试应检查程序是否尝试对系统进行数据请求调用并返回一些数据。

The way you would essentially switch System A with the mock object is using the patch. The patch temporarily replaces your object with a different object. In the case above, we would us the patch function to replace system A with the mock object in program A.

从本质上来说,使用模拟对象切换系统A的方式是使用补丁 。 该修补程序将您的对象临时替换为其他对象。 在上述情况下,我们将使用补丁函数将程序A中的模拟对象替换为系统 A。

用模拟修补和替换对象的方法 (Ways to Patch & Replace an Object with a Mock)

In Python 3, there are three common ways to patch an object:

在Python 3中,有三种修补对象的常用方法:

  1. Decorator

    装饰器
  2. Context Manager

    上下文管理器
  3. Inline

    排队

In turn, we will go through the these methods of using the patch with example code. The example we will unit test involves two functions; get_data() and connect_to_db().

反过来,我们将介绍将补丁与示例代码一起使用的所有方法。 我们将进行单元测试的示例涉及两个功能: get_data()connect_to_db()

# my_module.pydef get_data():
db = connect_to_db()
result = db.query_all_data()
return resultdef connect_to_db():
...

For unit testing purposes, we do not want to connect to the database and query a table. We want to test that we are calling the database and that some data is returned. By doing it this way, even if the database server crashes, our unit tests will not fail because of an extraneous variable outside the scope of our function declaration.

为了进行单元测试,我们不想连接到数据库并查询表。 我们要测试是否正在调用数据库并返回了一些数据。 通过这种方式,即使数据库服务器崩溃,我们的单元测试也不会因函数声明范围之外的外部变量而失败。

装饰器 (Decorator)

The decorator, denoted by the @ symbol above the function definition, is used to patch a callable Python object before the unit test is ran. The way that decorators would work in this context is the database connection will be replaced with a mock object and then the unit test will execute. Therefore, you will not be connecting to the database but rather the configured mock database object.

装饰器 (在函数定义上方用@符号表示)用于在运行单元测试之前修补可调用的Python对象。 装饰器在这种情况下的工作方式是将数据库连接替换为模拟对象,然后执行单元测试。 因此,您将不会连接到数据库,而是连接到已配置的模拟数据库对象。

Below shows a code snippet of using a decorator to unit test the get_url_html() function:

下面显示了使用装饰器对get_url_html()函数进行单元测试的代码片段:

# test_my_module.pyimport unittest
from my_module import get_data
from unittest.mock import Mock, patch@patch('my_module.connect_to_db')
def test_get_data(self, mock_db):
mock_db.return_value.query_all_data.return_value = 'result data'
result = get_data() self.assertEqual(result, 'result data')
self.assertEqual(mock_db.call_count, 1')
self.assertEqual(mock_db.query_all_data.call_count, 1)

We decorate out test function with the patch to the function that we want to replace with a mock object (connect_to_db). When patching using a decorator, you must pass an argument of the object as an input to the test function (mock_db). Then, we set the get_query_all_data() method of the mock_db object to return ‘the text result_data’. Now that the connect_to_db() function has been replaced with our mock_db object , we execute the get_data() function and assign it to the result variable.

我们用补丁来装饰测试功能,该补丁是我们要用模拟对象( connect_to_db )替换的功能。 使用装饰器进行修补时,必须将对象的参数作为输入传递给测试函数( mock_db )。 然后,我们将嘲笑数据库对象的get_query_all_data()方法设置为返回“文本result_data”。 现在, connect_to_db()函数已替换为我们的mock_db对象,我们将执行get_data()函数并将其分配给结果变量。

AssertEquals is used to for three reasons in our test_get_data function:

在我们的test_get_data函数中,使用AssertEquals的原因有三个:

  1. Check that the result of get_data() function returns the result_data as we configured

    检查get_data()函数的结果是否返回我们配置的result_data

  2. Check that we have tried to connect to our database object. We should only call our database once. Call count is a special attribute of the mock object that totals the number of times the mock object has been called

    检查我们是否尝试连接到数据库对象。 我们只应该调用我们的数据库一次。 调用计数是模拟对象的一个​​特殊属性,该属性总计模拟对象被调用的次数
  3. Check that we have executed a query method to retrieve all data. We should only call the query_all_data() function once

    检查我们是否已执行查询方法以检索所有数据。 我们只应该调用一次query_all_data()函数

上下文管理器 (Context Manager)

Context managers can be used to patch objects only within the block of code. In the same way as the decorator example, we patch the database connection with mock_db and check that the respective elements of the function have been called,

上下文管理器仅可用于在代码块内修补对象。 以与装饰器示例相同的方式,我们用mock_db修补数据库连接,并检查是否已调用函数的各个元素,

# test_my_module.pydef test_get_data(self):

with patch('my_module.connect_to_db', return_value=Mock()) as mock_db:

mock_db.return_value.query_all_data.return_value = 'result data'
result = get_data()

self.assertEqual(result, 'result data')
self.assertEqual(mock_db.call_count, 1')
self.assertEqual(mock_db.query_all_data.call_count, 1)

The key difference between patching using a decorator compared to a context manager is within the test_get_data(), you do not need to pass in mock_db as an argument. If the function was called outside of the context manager, the connect_to_db method will not be patched, therefore, you would actually be connecting to the database. Context managers are useful for configuring mock objects in a contained fashion.

使用装饰器进行修补与使用上下文管理器进行修补之间的主要区别在于test_get_data()内 ,您无需传递模拟数据库作为参数。 如果在上下文管理器外部调用该函数,则将不会修补connect_to_db方法,因此,实际上您将连接到数据库。 上下文管理器对于以包含方式配置模拟对象很有用。

排队 (Inline)

Another alternative to the two patching methods above is inline. If you have wrote unit tests before, you re likely to have seen the setUp() and tearDown() methods of the unittest library. For more informtion about these methods, visit the Python unittest documentation.

上面两种修补方法的另一种替代方法是内联。 如果您之前编写过单元测试,则很可能已经看到了unittest库的setUp()和tearDown()方法。 有关这些方法的更多信息,请访问Python unittest文档

The setUp() and tearDown() methods allow you to define instructions that will be executed before and after each test method.

使用setUp()和tearDown()方法可以定义将在每个测试方法之前和之后执行的指令。

The difference to using inline patching is you must start and stop the patch; often within the setUp and tearDown methods respectively.

使用内联修补程序的区别在于您必须启动和停止修补程序。 通常分别在setUp和tearDown方法中。

# test_my_module.pydef test_get_data(self):

mock_db = patch('my_module.connect_to_db').start()
mock_db.return_value.query_all_data.return_value = 'result data'
result = get_data() self.assertEqual(actual, 'result data')
self.assertEqual(mock_db.call_count, 1)
self.assertEqual(mock_db.query_all_data.call_count, 1) mock_db.stop()

We patch the connect_to_db and assign it to the mock_db variable. As demonstrated in the code above, the start() and stop() method is used to to activate (or deactivate) the patching of an object. The only difference in the code demonstration above is these start and stop methods. Remember to start and stop the patch to avoid potential issues with the mock object call_count cumulatively adding for each unit test.

我们修补connect_to_db并将其分配给mock_db变量。 如上面的代码所示, start()stop()方法用于激活(或取消激活)对象的修补。 上面代码演示中的唯一区别是这些启动和停止方法。 请记住要启动和停止补丁程序,以避免为每个单元测试累计添加的模拟对象call_count潜在的问题。

选择模拟实现方法 (Choosing the Mock Implementation Method)

All three methods above are valid and equally as effective to patch a target object with a mock. From my experience, there are two elements to consider when deciding the method to use:

上面的所有三种方法都是有效的,并且同等有效地使用模拟补丁修补目标对象。 根据我的经验,在确定使用方法时要考虑两个因素:

  1. Choose the method that makes sense to you

    选择对您有意义的方法
  2. Be consistent in your approach to applying the patch

    一致地应用补丁

Everyone unit tester has their personal preference on the way to mock an object. Some may find a context manager easier to read, whereas others may prefer to declare all their mock objects via decorators at the top of the function. But try not to use both. When those unit tests are visited in the future, the tester will see the approach you have taken across which makes it easier to amend tests if or when they fail.

每个人的单元测试人员在模拟对象的方式上都有自己的偏好。 一些人可能会发现上下文管理器更易于阅读,而其他人可能更喜欢通过函数顶部的装饰器声明其所有模拟对象。 但是,请不要同时使用两者。 将来访问那些单元测试时,测试人员将看到您采用的方法,如果在测试失败时或失败时,可以更轻松地修改测试。

结论 (Conclusion)

Now that you know the wonderful ways to patch an object with a mock, experiment and have fun unit testing your programs!

现在,您已经知道了通过模拟,实验和对单元进行有趣的单元测试来修补对象的绝妙方法!

  • Here is a useful resource to learning how to patch an object successfully.

    这是学习如何成功修补对象的有用资源

  • Write functions with complete unit tests by testing different scenarios to see if you function can pass different tests using Hypothesis.

    通过测试不同的场景来编写具有完整单元测试的功能,以查看您的功能是否可以使用假设通过不同的测试。

翻译自: https://medium.com/@aaronginder/3-ways-to-implement-the-mock-during-python-unit-testing-f96cc9f5d589

模拟退火python实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值