单元测试底漆
当为插件创建单元测试时,推荐的做法是将它们存储在插件目录的根目录unit_test文件夹中。
对于较大的插件,我们建议将操作、连接、有效负载和触发器分离到子文件夹中。这将使您能够根据需要运行单独的测试。在单元测试目录中创建子文件夹会影响单元测试导入过程。
创建单元测试
单元测试必须遵循特定的格式。在准备编写单元测试时注意以下几点:
- TestEncode类必须从TestCase继承
- 所有测试都是TestEncode类中的函数,它们必须以
试验_
下面是一个正确编写的单元测试示例:
python
1.
从unittest进口测试用例
2.
3.
班测试代码(测试用例):
4.
deftest_run(自我):
5.
通过
运行单元测试
一旦你编写了TestEnclose类,你就可以用下列方式之一在PyCharm中运行它:
在PyCharm中,单击出现在类左侧的绿色箭头。
从命令行运行测试。有关更多信息,请参见在这里.
注意:如果你从命令行运行,你会遇到Python路径问题。为了修复这个问题,我使用了以下代码。
python
1.
从unittest进口测试用例
2.
进口sys
3.
进口操作系统
4.
5.
working_path=操作系统.getcwd()
6.
sys.路径.插入(0,“. . /”)
7.
8.
从icon_azure_ad_admin.行动进口禁用用户帐户
这段代码将插件结构的根目录添加到Python路径中。这允许您从图标
没有外部调用的单元测试
编写并运行单元测试之后,就可以开始测试代码了。
在测试代码之前,必须具备以下条件:
- 一个有效的plugin.spec.yaml文件
- 生成的插件
python
1.
从unittest进口测试用例
2.
从komand_base64.行动进口编码
3.
进口日志记录
4.
5.
班测试代码(测试用例):
6.
deftest_run(自我):
7.
日志=日志记录.getlog(“测试”)
8.
测试编码器=编码()
9
10
params={
11
“内容”:“看,妈妈,单元测试!"
12
}
13
14
测试编码器.日志记录器=日志
15
实际=测试编码器.运行(params)
16
17
预期={“数据”:“TG9vayBtb20sIHVuaXQgdGVzdHMh”}
18
19
自我.资产质量(实际,预期)
接下来,您需要配置以下设置:
- 日志记录器
- 插件将需要一个日志记录器。我们通过导入日志并使用logging. getlogger()来做到这一点。多亏了Python的魔力,你可以简单地用< plugin >将其注入类中。日志= <日志>
- 参数
- 如果要运行run函数,您将需要参数。为了快速创建它们,您可以从.json测试文件中复制它们。(如果你没有这些,用它们生成。/ run.sh - c样品)
- 预期
- 如果使用复杂的输出,此设置将节省时间。设置应为“”然后在assertEqual上设置断点。调试单元测试。它应该在assert语句上中断,并且您将在调试窗格的监视窗口中显示所有变量值。如果实际值正确,只需复制该值并将其粘贴到预期值中即可。
下面是所有可用的断言语句:https://docs.python.org/3/library/unittest.html#test-cases
通常,您将使用assertEquals,但有几个测试断言非常有用,例如assertTrue和assertRaises。
使用外部调用进行测试
快速开发外部调用的一种方法是使用Postman来确保API调用正确,将有效负载复制到插件项目中,并模拟API调用。对于大型复杂调用,这可以节省大量时间。
假设:您知道如何使用Postman,并且可以使用该工具进行API调用。如果您更熟悉cURL,它也可以工作。
下面的例子来自Office 365电子邮件插件。这是大量的代码,但它比看起来容易得多。
这只是将有效负载读取为文本,这使得模拟API调用更加容易。
python
1.
这只是读取有效载荷在里面作为文本,这使得模拟API调用更加容易.
2.
3.
#从文件中获取真正的有效负载
4.
def读取\u文件\u到\u字符串(文件名):
5.
具有开放(文件名)作为my_file:
6.
返回my_file.读()
这段代码模拟了request .get()方法。request .get()方法模拟一个Python命令,使其成为运行测试的有效方法。
python
1.
这个方法将被mock使用来替换request .get
2.
defmocked_requests_get(*args,**关键字参数):
3.
班模拟反应:
4.
def__init__(自我,json_data,状态代码):
5.
自我.json_data=json_data
6.
自我.状态代码=状态代码
7.
自我.文本=“这是一些错误文本”
8.
9
defjson(自我):
10
返回json.加载(自我.json_data)
11
12
#因为这是基础unit_test文件夹下的文件夹,如果我们是
13
#运行整个套件,或者只是这些测试。
14
实际路径=操作系统.路径.目录名(操作系统.路径.realpath(__文件__))
15
actual_joined_path=操作系统.路径.参加(实际路径,“有效载荷/从用户.json获取消息”)
16
从用户有效负载获取消息=读取\u文件\u到\u字符串(actual_joined_path)
17
18
如果args[0]=='https://login.microsoftonline.com/test_tenant_id/oauth2/token':
19
返回模拟反应({“access_token”:“test_api_token6”},200)
20.
如果args[0]=='https://graph.microsoft.com/v1.0/test_tenant_id/users/bob@hotmail.com/messages?$search=“from:from”&$top=250':
21
返回模拟反应(从用户有效负载获取消息,200)
22
23
打印(F "mocked_requests_get failed looking for:{args[0]}")
24
返回模拟反应(没有一个,404)
在设置设置时注意以下事项:
- 模拟对象:
- 实际上,这个类模仿了两件事。request .get()及其响应对象的行为。在这个块的前几行中,您将看到我们创建了一个包含在这个方法中的内联类。这将是mock被调用时返回的东西。
- Python路径注意
- 在那下面,你会看到我们阅读有效载荷。我必须对路径做一个技巧,以确保Python可以找到我们的有效负载,不管这个脚本在哪里运行。如果在运行所有测试时从unit_tests的根目录运行此脚本,则当前工作目录(CWD)将与仅运行此套件或仅运行此套件中的测试不同。
- ARGS
- 我想看看我们有什么论点,看看我们试图称之为什么。如果参数与我们期望的调用之一匹配,则返回模拟响应。
- 错误
- 如果传入的参数与我期望的任何URL都不匹配,我将打印该URL并使用404进行紧急救援。打印很方便,因此您可以快速查看失败的内容。404非常方便,因为它允许我们在代码中测试错误处理。
在这段代码中,我创建了一个假连接类,可以传递给我的操作类。
python
1.
#模拟连接
2.
班模拟连接:
3.
def__init__(自我):
4.
自我.租户=“test_tenant_id”
5.
自我.auth_token=“test_api_token”
6.
7.
def获取标题(自我,api_令牌):
8.
返回{
9
“thisisaheader”:“这就是价值”,
10
“api_token”:自我.auth_token
11
}
12
13
defget_auth_token(自我):
14
返回自我.auth_token
这段代码是非常特定于O365插件的,但是我想要说明的是,您必须为我们的插件使用的一些公共类创建模拟类。
最后……实际的测试:
python
1.
@mock.补丁(“requests.get”,side_effect=mocked_requests_get)
2.
def测试\u从用户获取\u消息\u(自我,mock_get):
3.
get_messages=GetEmailFromUser()
4.
get_messages.连接=模拟连接()
5.
实际=get_messages.从用户处获取消息(“bob@hotmail.com”,“美元搜索= "来自:" & $ = 250 ')
6.
7.
自我.assertTrue(len(实际),3.)
8.
自我.资产质量(实际[2.].得到(“身份证”),‘AAMKADI3MZC1ZTG3LTIZYWETNNMNI1HZDQ5LTBIMJAZYZA3ZTHHYWBGAAAAAAXDVRPC8Q6SQGLTJ9IB-SGBwC8UQDN7ObVSLWQuxHJ-dDTAAE-L_Q7AAC8UQDN7ObVSLWQuxHJ-dDTAAE-MJpHAAA’)
- 模拟补丁
- 这里需要注意的重要事情是@mock。补丁装饰。这是一个巧妙的函数,它将用您指定的方法替换一个函数的行为。在这种情况下,我们接受请求。得到and replacing that functionality with our mocked_requests_get method from above.
这里有更多关于嘲笑
例外情况下的单元测试
对于非传统的单元tess,我们可以做的最重要的事情之一是异常处理和异常错误场景(想要从一个状态代码为200的响应中得到错误的JSON吗?这就是测试它的方法!)
python
1.
deftest_make_kql_for_request_throws_exception(自我):
2.
get_messages=GetEmailFromUser()
3.
4.
具有自我.assertRaises(PluginException):
5.
get_messages.提出请求时发出请求("","","",250)
在本例中,我们为make_kql_for_请求生成错误输入,这会导致它抛出异常。我们希望确保它专门抛出PluginException,而不是用户可能不知道如何处理的其他错误。
以以下内容开头具有允许我们捕获异常并验证我们有正确的异常。
触发器的单元测试
测试我们的触发器非常困难,因为它们本质上是一个无尽的循环。我们建议您将逻辑从触发器的“主循环”移到单独的函数中,并通过直接的单元测试对它们进行测试。
最终,您仍然需要验证触发器“主循环”是否有效。下面的示例演示如何设置调用和超时装饰器,以确保不会遇到任何异常。
python
1.
# timeout decorator允许我们在不失败测试的情况下终止'while True'循环
2.
@超车超时
3.
@超时装饰器.超时(3.)
4.
@mock.补丁(“requests.get”,side_effect=mocked_requests_get)
5.
deftest_microsoft_message_received(自我,mock_get):
6.
先生=收到电子邮件()
7.
params={
8.
“邮箱\u id”:TEST_MAILBOX_ID,
9
“subject_query”:测试查询,
10
“间隔”:1.
11
}
12
先生.连接=模拟连接()
13
先生.日志流=MockDispatcher()
14
先生.调度员=MockDispatcher()
15
先生.日志记录器=日志记录.getlog(“测试记录器”)
16
先生.当前时间=玛雅.MayaDT(“2019-08-05T14:57:40Z”)
17
18
先生.运行(params)
@超车超时-告诉测试框架超时正在通过测试
@timeout_decorator.timeout (3)-告诉测试在3秒后超时。当间隔设置为1时,这将给我们两个循环,足以验证我们是否通过了此测试。

