TestCenter Reference
BDD.py
Go to the documentation of this file.
2# Copyright 2013, MeVis Medical Solutions AG
3#
4# The user may use this file in accordance with the license agreement provided with
5# the Software or, alternatively, in accordance with the terms contained in a
6# written agreement between the user and MeVis Medical Solutions AG.
7#
8# For further information use the contact form at https://www.mevislab.de/contact
9#
10
11"""Tools for writing human readable, behavioral tests.
12
13The functions, decorators and classes defined in this module enable
14you to write tests describing the desired behavior of a MeVisLab
15module (or any other Python object).
16
17A typical behavioral test looks like this:
18
19def TEST_a_behavioral_test():
20 Given().a_precondition(). \
21 When().you_do_something(). \
22 Then().something_happens()
23
24i.e. it is the concatenation of several function calls, or, in other words,
25it is a sentence consisting of a Given clause, a When clause, and a Then
26clause.
27
28Given(), When(), and Then() are predefined functions marking the start of
29the Given clause (and of the whole sentence), the When clause, and the Then
30clause, respectively.
31
32There is another predefined function, And(), which can be used to concatenate
33several custom functions of the same type, e.g.
34
35 Given().precondition1(). \
36 And().precondition2(). \
37 [...]
38
39The other functions are custom functions that are defined with the help
40of three decorators: GivenClause, WhenClause, and ThenClause. (The decorators
41add the decorated functions to the context class so that they can be called
42as member functions.)
43
44The Given() function creates and returns a context object for the test. All
45other functions are member functions of this context object. These functions
46also return the context object. This allows arbitrary chaining of those
47functions. By adding attributes to the context object we can pass arbitrary
48state from one function to the next.
49
50See ExampleBDDTestCase in MeVisLab/Examples for an example.
51
52For more information on Behavior Driven Development (BDD) check the Internet.
53
54If you need a more powerful BDD-style language then have a look at one of the
55existing Python BDD modules like behave, freshen, lettuce, etc.
56"""
57
58import functools
59
60from TestSupport import Logging
61
62
63def Given():
64 """Initiates a sentence describing a desired behavior.
65
66 Creates and returns the context object for the test.
67 """
68 return _BDDContext()
69
70def GivenClause(func):
71 """Decorator for defining a Given clause.
72
73 The first argument that is passed to the decorated function is the
74 context object. Custom parameters are passed to the decorated
75 function after the context object.
76
77 The decorated function always returns the context object.
78
79 Example:
80 @GivenClause
81 def a_precondition(testContext):
82 # perform the setup of the test, e.g. by parameterizing a TestPattern
83 # module
84 """
85 return _BDDClause('Given')(func)
86
87def WhenClause(func):
88 """Decorator for defining a When clause.
89
90 The first argument that is passed to the decorated function is the
91 context of the test case. Custom parameters are passed to the decorated
92 function after the context.
93
94 The decorated function always returns the context object.
95
96 Example:
97 @WhenClause
98 def you_do_something(testContext):
99 # do whatever shall result in a certain behavior, e.g. touch a field
100 """
101 return _BDDClause('When')(func)
102
103def ThenClause(func):
104 """Decorator for defining a Then clause.
105
106 The first argument that is passed to the decorated function is the
107 context of the test case. Custom parameters are passed to the decorated
108 function after the context.
109
110 The decorated function always returns the context object.
111
112 Example:
113 @ThenClause
114 def something_happens(testContext):
115 # check for the expected behavior, e.g. by comparing a field value
116 # with an expected value
117 """
118 return _BDDClause('Then')(func)
119
120
121# Internal stuff
122
124 """Context of a BDD test case.
125
126 Instances of this class are created with Given(). All functions defined
127 with the clause decorators are added to _BDDContext.
128 """
129
130 def __init__(self):
131 self._state = 'Given'
132
133 def And(self):
134 """Conjunction for joining two clauses of the same type.
135
136 This method does nothing except returning the context. It is merely
137 syntactic sugar for joining two clauses of the same type, i.e. two
138 Given clauses, two When clauses, or two Then clauses.
139 """
140 return self
141
142 def With(self):
143 """Conjunction for joining two clauses of the same type.
144
145 This method does nothing except returning the context. It is merely
146 syntactic sugar for joining two clauses of the same type, i.e. two
147 Given clauses, two When clauses, or two Then clauses.
148 """
149 return self
150
151 def When(self):
152 """Conjunction for marking the start of the When part.
153
154 This method starts the When part of the sentence describing the
155 desired behavior. It returns the context.
156 """
157 self._state = 'When'
158 return self
159
160 def Then(self):
161 """Conjunction for marking the start of the Then part.
162
163 This method starts the Then part of the sentence describing the
164 desired behavior. It returns the context.
165 """
166 self._state = 'Then'
167 return self
168
169 def __getattr__(self, name):
170 """Returns Given/When/Then method corresponding to @a name."""
171 prefix = self._state + '_'
172 if not name.startswith(prefix):
173 return getattr(self, prefix + name)
174 else:
175 raise AttributeError('Attribute with name "%s" not found.' % name)
176
177def _BDDClause(clauseType):
178 """Internal decorator used for defining clauses of different types."""
179 def func_wrapper(func):
180 @functools.wraps(func)
181 def wrapper(self, *args, **kwargs):
182 func(self, *args, **kwargs)
183 return self
184 setattr(_BDDContext, clauseType + '_' + func.__name__, wrapper)
185 return func_wrapper
__getattr__(self, name)
Definition BDD.py:169
_BDDClause(clauseType)
Definition BDD.py:177
WhenClause(func)
Definition BDD.py:87
ThenClause(func)
Definition BDD.py:103
GivenClause(func)
Definition BDD.py:70