第六讲:日志模块
培训目标
- 掌握日志的分级思想,不同级别的日志落点文件,日志内容本身的组织规范。
- 掌握常用的断言函数,断言内容本身的构成要素,写法规范。
课程笔记
一、logging
1. 在哪里学习?
文档:https://docs.python.org/3.7/library/logging.config.html
https://docs.python.org/3.7/library/logging.html
我个人推荐的文章:python之配置日志的几种方式|Python之日志处理(logging模块)
2. logging 模块四大组件
组件 | 说明 |
---|---|
loggers | 提供应用程序代码直接使用的接口 |
handlers | 用于将日志记录发送到指定的目的位置 |
filters | 提供更细粒度的日志过滤功能,用于决定哪些日志记录将会被输出(其它的日志记录将会被忽略) |
formatters | 用于控制日志信息的最终输出格式 |
二、如何使用 behave
1. 在哪里学习?
- 基础概念、配置、操作https://behave.readthedocs.io/en/stable/
2. behave 测试框架由哪些元素构成
https://behave.readthedocs.io/en/latest/tutorial.html#
- feature文件
- step实现
环境控制?
a. feature 文件
https://behave.readthedocs.io/en/latest/api.html#runner-operation
# -- SIMPLIFIED GHERKIN GRAMMAR (for Gherkin v6):
# CARDINALITY DECORATOR: '*' means 0..N (many), '?' means 0..1 (optional)
# EXAMPLE: Feature
# A Feature can have many Tags (as TaggableStatement: zero or more tags before its keyword).
# A Feature can have an optional Background.
# A Feature can have many Scenario(s), meaning zero or more Scenarios.
# A Feature can have many ScenarioOutline(s).
# A Feature can have many Rule(s).
Feature(TaggableStatement):
Background?
Scenario*
ScenarioOutline*
Rule*
Background:
Step* # Background steps are injected into any Scenario of its scope.
Scenario(TaggableStatement):
Step*
ScenarioOutline(ScenarioTemplateWithPlaceholders):
Scenario* # Rendered Template by using ScenarioOutline.Examples.rows placeholder values.
Rule(TaggableStatement):
Background? # Behave-specific extension (after removal from final Gherkin v6).
Scenario*
ScenarioOutline*
b. step 实现
feature文件:
Scenario: Search for an account
Given I search for a valid account
Then I will see the account details
step 代码实现:
@given('I search for a valid account')
def step_impl(context):
context.browser.get('http://localhost:8000/index')
form = get_element(context.browser, tag='form')
get_element(form, name="msisdn").send_keys('61415551234')
form.submit()
@then('I will see the account details')
def step_impl(context):
elements = find_elements(context.browser, id='no-account')
eq_(elements, [], 'account not found')
h = get_element(context.browser, id='account-head')
ok_(h.text.startswith("Account 61415551234"),
'Heading %r has wrong text' % h.text)
c. 环境控制
在environment.py模块中定义了在指定事件发生前后执行的代码
before\_step(context, step), after\_step(context, step)
These run before and after every step.
before\_scenario(context, scenario), after\_scenario(context, scenario)
These run before and after each scenario is run.
before\_feature(context, feature), after\_feature(context, feature)
These run before and after each feature file is exercised.
before\_tag(context, tag), after\_tag(context, tag)
These run before and after a section tagged with the given name. They are invoked for each tag encountered in the order they’re found in the feature file. Seecontrolling things with tags.
before\_all(context), after\_all(context)
These run before and after the whole shooting match.
3. 以上元素的调用顺序
https://behave.readthedocs.io/en/latest/api.html#runner-operation
https://behave.readthedocs.io/en/latest/gherkin.html#background
# -- PSEUDO-CODE:
# HOOK: before_tag(), after_tag() is called for Feature, Rule, Scenario
ctx = createContext()
call-optional-hook before_all(ctx)
for feature in all_features:
for tag in feature.tags:
call-optional-hook before_tag(ctx, tag)
call-optional-hook before_feature(ctx, feature)
for run_item in feature.run_items: # CAN BE: Rule, Scenario, ScenarioOutline
execute_run_item(run_item, ctx)
call-optional-hook after_feature(ctx, feature)
for tag in feature.tags:
call-optional-hook after_tag(ctx, tag)
call-optional-hook after_all(ctx)
function execute_run_item(run_item, ctx):
if run_item isa ScenarioOutline:
# -- CASE: ScenarioOutline
# HINT: All Scenarios are already created from Example(s) rows.
scenario_outline = run_item
for scenario in scenario_outline.scenarios:
execute_run_item(scenario, ctx)
else if run_item isa Scenario:
# -- CASE: Scenario
# HINT: Background steps are injected before scenario steps.
scenario = run_item
for tag in scenario.tags:
call-optional-hook before_tag(ctx, tag)
call-optional-hook before_scenario(ctx, scenario)
for step in scenario.steps:
call-optional-hook before_step(ctx, step)
step.run(ctx)
call-optional-hook after_step(ctx, step)
call-optional-hook after_scenario(ctx, scenario)
for tag in scenario.tags:
call-optional-hook after_tag(ctx, tag)
4. context 属性的生命周期
https://behave.readthedocs.io/en/latest/context\_attributes.html#user-attributes
三、断言 hamcrest
1. 在那里学习?
文档:https://pyhamcrest.readthedocs.io/en/v2.0.2/
代码:https://github.com/hamcrest/PyHamcrest
2. 预定义的 matcher
* Object
* `equal_to`\- match equal object
* `has_length`\- match`len()`
* `has_property`\- match value of property with given name
* `has_properties`\- match an object that has all of the given properties.
* `has_string`\- match`str()`
* `instance_of`\- match object type
* `none`,`not_none`\- match`None`, or not`None`
* `same_instance`\- match same object
* `calling, raises`\- wrap a method call and assert that it raises an exception
* Number
* `close_to`\- match number close to a given value
* `greater_than`,`greater_than_or_equal_to`,`less_than`,`less_than_or_equal_to`\- match numeric ordering
* Text
* `contains_string`\- match part of a string
* `ends_with`\- match the end of a string
* `equal_to_ignoring_case`\- match the complete string but ignore case
* `equal_to_ignoring_whitespace`\- match the complete string but ignore extra whitespace
* `matches_regexp`\- match a regular expression in a string
* `starts_with`\- match the beginning of a string
* `string_contains_in_order`\- match parts of a string, in relative order
* Logical
* `all_of`\-`and`together all matchers
* `any_of`\-`or`together all matchers
* `anything`\- match anything, useful in composite matchers when you don't care about a particular value
* `is_not`,`not_`\- negate the matcher
* Sequence
* `contains`\- exactly match the entire sequence
* `contains_inanyorder`\- match the entire sequence, but in any order
* `has_item`\- match if given item appears in the sequence
* `has_items`\- match if all given items appear in the sequence, in any order
* `is_in`\- match if item appears in the given sequence
* `only_contains`\- match if sequence's items appear in given list
* `empty`\- match if the sequence is empty
* Dictionary
* `has_entries`\- match dictionary with list of key-value pairs
* `has_entry`\- match dictionary containing a key-value pair
* `has_key`\- match dictionary with a key
* `has_value`\- match dictionary with a value
* Decorator
* `calling`\- wrap a callable in a deferred object, for subsequent matching on calling behaviour
* `raises`\- Ensure that a deferred callable raises as expected
* `described_as`\- give the matcher a custom failure description
* `is_`\- decorator to improve readability - see Syntactic sugar below
练习题
题目一
使用字典的方式对日志进行配置(yaml)
题目二
配置两个 handle 分别为对应 debug 级别日志和 info 级别日志,写入两个不同的日志文件。
题目三
日志的 formatter 要能展示
- 日志的时间
- 日志的文件名、函数名、行号
- 日志的级别
题目四
打印 error、exception、debug、info、warning、critical 级别的日志。