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
60
61def Given():
62 """Initiates a sentence describing a desired behavior.
63
64 Creates and returns the context object for the test.
65 """
66 return _BDDContext()
67
68
69def GivenClause(func):
70 """Decorator for defining a Given clause.
71
72 The first argument that is passed to the decorated function is the
73 context object. Custom parameters are passed to the decorated
74 function after the context object.
75
76 The decorated function always returns the context object.
77
78 Example:
79 @GivenClause
80 def a_precondition(testContext):
81 # perform the setup of the test, e.g. by parameterizing a TestPattern
82 # module
83 """
84 return _BDDClause("Given")(func)
85
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
103
104def ThenClause(func):
105 """Decorator for defining a Then clause.
106
107 The first argument that is passed to the decorated function is the
108 context of the test case. Custom parameters are passed to the decorated
109 function after the context.
110
111 The decorated function always returns the context object.
112
113 Example:
114 @ThenClause
115 def something_happens(testContext):
116 # check for the expected behavior, e.g. by comparing a field value
117 # with an expected value
118 """
119 return _BDDClause("Then")(func)
120
121
122# Internal stuff
123
124
126 """Context of a BDD test case.
127
128 Instances of this class are created with Given(). All functions defined
129 with the clause decorators are added to _BDDContext.
130 """
131
132 def __init__(self):
133 self._state = "Given"
134
135 def And(self):
136 """Conjunction for joining two clauses of the same type.
137
138 This method does nothing except returning the context. It is merely
139 syntactic sugar for joining two clauses of the same type, i.e. two
140 Given clauses, two When clauses, or two Then clauses.
141 """
142 return self
143
144 def With(self):
145 """Conjunction for joining two clauses of the same type.
146
147 This method does nothing except returning the context. It is merely
148 syntactic sugar for joining two clauses of the same type, i.e. two
149 Given clauses, two When clauses, or two Then clauses.
150 """
151 return self
152
153 def When(self):
154 """Conjunction for marking the start of the When part.
155
156 This method starts the When part of the sentence describing the
157 desired behavior. It returns the context.
158 """
159 self._state = "When"
160 return self
161
162 def Then(self):
163 """Conjunction for marking the start of the Then part.
164
165 This method starts the Then part of the sentence describing the
166 desired behavior. It returns the context.
167 """
168 self._state = "Then"
169 return self
170
171 def __getattr__(self, name):
172 """Returns Given/When/Then method corresponding to @a name."""
173 prefix = self._state + "_"
174 if not name.startswith(prefix):
175 return getattr(self, prefix + name)
176 else:
177 raise AttributeError('Attribute with name "%s" not found.' % name)
178
179
180def _BDDClause(clauseType):
181 """Internal decorator used for defining clauses of different types."""
182
183 def func_wrapper(func):
184 @functools.wraps(func)
185 def wrapper(self, *args, **kwargs):
186 func(self, *args, **kwargs)
187 return self
188
189 setattr(_BDDContext, clauseType + "_" + func.__name__, wrapper)
190
191 return func_wrapper
__getattr__(self, name)
Definition BDD.py:171
_BDDClause(clauseType)
Definition BDD.py:180
WhenClause(func)
Definition BDD.py:87
ThenClause(func)
Definition BDD.py:104
GivenClause(func)
Definition BDD.py:69