1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
|
Feature: Use a user-defined Formatter
As a behave user
I want to be able to provide own, user-defined formatters
So that I am able to add a new, user-defined formatters
when I need other output formats (or override existing ones).
. SPECIFICATION:
. * A user-defined formatter must inherit from the "Formatter" class.
. * A user-defined formatter can be specified on command-line
. by using a scoped class name as value for the '--format' option.
. * A user-defined formatter can be registered by name
. by using the "behave.formatters" section in the behave config file.
.
. SCOPED CLASS NAME (for formatter.class):
. * my.module_name:ClassName (preferred: single colon separator)
. * my.module_name::ClassName (alternative: double colon separator)
@setup
Scenario: Feature Setup
Given a new working directory
And a file named "features/steps/passing_steps.py" with:
"""
from behave import step
@step('{word:w} step passes')
def step_passes(context, word):
pass
@step('{word:w} step fails')
def step_fails(context, word):
assert False, "XFAIL-STEP"
"""
And a file named "features/passing.feature" with:
"""
Feature:
Scenario: Alice
Given a step passes
When another step passes
Scenario: Bob
Then some step passes
"""
And an empty file named "behave_ext/__init__.py"
And a file named "behave_ext/formatter_one.py" with:
"""
from behave.formatter.base import Formatter
class NotAFormatter(object): pass
class SuperFormatter(Formatter):
name = "super"
description = "Super-duper formatter."
"""
And a file named "behave_ext/formatter_foo.py" with:
"""
from behave.formatter.base import Formatter
class FooFormatter(Formatter):
name = "foo"
description = "User-specific FOO formatter."
class FooFormatter2(Formatter):
description = "User-specific FOO2 formatter."
"""
And a file named "behave_ext/formatter_bar.py" with:
"""
from behave.formatter.base import Formatter
class BarFormatter(Formatter):
description = "User-specific BAR formatter."
"""
@use_formatter.class
Scenario: Use a known, valid user-defined formatter with scoped class name
When I run "behave -f behave_ext.formatter_one:SuperFormatter features/passing.feature"
Then it should pass with:
"""
2 scenarios passed, 0 failed, 0 skipped
3 steps passed, 0 failed, 0 skipped, 0 undefined
"""
@use_formatter.class
Scenario: Use a known, valid user-defined formatter (with double colon)
ALTERNATIVE: Can currently use a double colon as separator, too.
When I run "behave -f behave_ext.formatter_one::SuperFormatter features/passing.feature"
Then it should pass with:
"""
2 scenarios passed, 0 failed, 0 skipped
3 steps passed, 0 failed, 0 skipped, 0 undefined
"""
@use_formatter.class
Scenario Outline: Use built-in formatter "<formatter.name>" like a user-defined formatter
When I run "behave -f <formatter.class> features/passing.feature"
Then it should pass with:
"""
2 scenarios passed, 0 failed, 0 skipped
3 steps passed, 0 failed, 0 skipped, 0 undefined
"""
Examples:
| formatter.name | formatter.class |
| plain | behave.formatter.plain:PlainFormatter |
| pretty | behave.formatter.pretty:PrettyFormatter |
@problematic
@use_formatter.class
Scenario Outline: Use a problematic user-defined formatter (<case>)
When I run "behave -f <formatter.class> features/passing.feature"
Then it should fail with:
"""
error: format=<formatter.class> is unknown
"""
Examples:
| formatter.class | case |
| my.unknown_module:SomeFormatter | Unknown module |
| behave_ext.formatter_one:UnknownClass | Unknown class |
| behave_ext.formatter_one:NotAFormatter | Invalid Formatter class |
@formatter.registered_by_name
Scenario Outline: Register user-defined formatter by name: <formatter.name>
Given a file named "behave.ini" with:
"""
[behave.formatters]
foo = behave_ext.formatter_foo:FooFormatter
foo2 = behave_ext.formatter_foo:FooFormatter2
bar = behave_ext.formatter_bar:BarFormatter
"""
And note that "the schema: 'formatter.name = formatter.class' is used"
When I run "behave -f <formatter.name> features/passing.feature"
Then it should pass with:
"""
2 scenarios passed, 0 failed, 0 skipped
3 steps passed, 0 failed, 0 skipped, 0 undefined
"""
But the command output should not contain:
"""
error: format=<formatter.name> is unknown
"""
Examples:
| formatter.name | Comment |
| foo | First user-defined, registered formatter. |
| bar | Last user-defined, registered formatter. |
@formatter.registered_by_name
Scenario: Help-Format shows description of registered-by-name formatters
Given a file named "behave.ini" with:
"""
[behave.formatters]
foo = behave_ext.formatter_foo:FooFormatter
bar = behave_ext.formatter_bar:BarFormatter
"""
When I run "behave -f help"
Then it should pass with:
"""
Available formatters:
"""
And the command output should contain:
"""
bar User-specific BAR formatter.
"""
And the command output should contain:
"""
foo User-specific FOO formatter.
"""
@problematic
@formatter.registered_by_name
Scenario Outline: Use problematic, registered-by-name formatter: <case>
Given a file named "behave.ini" with:
"""
[behave.formatters]
<formatter.name> = <formatter.class>
"""
When I run "behave -f <formatter.name> features/passing.feature"
Then it should fail with:
"""
error: format=<formatter.name> is unknown
"""
Examples:
| formatter.name | formatter.class | case |
| unknown1 | my.unknown_module:SomeFormatter | Unknown module |
| unknown2 | behave_ext.formatter_one:UnknownClass | Unknown class |
| invalid1 | behave_ext.formatter_one:NotAFormatter | Invalid Formatter class |
|