robotframework-mock 0.2.0__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,389 @@
1
+ Metadata-Version: 2.4
2
+ Name: robotframework-mock
3
+ Version: 0.4.0
4
+ Summary: A Robot Framework library for mocking keywords in unit tests
5
+ Home-page: https://github.com/olesz/robotframework-mock
6
+ Author: Lajos Olah
7
+ Author-email: lajos.olah.jr@gmail.com
8
+ License: Apache-2.0
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Framework :: Robot Framework
17
+ Classifier: Framework :: Robot Framework :: Library
18
+ Requires-Python: >=3.10
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: robotframework>=7.0
22
+ Requires-Dist: tomli>=1.1.0; python_version < "3.11"
23
+ Dynamic: license-file
24
+
25
+ # robotframework-mock
26
+
27
+ A Robot Framework library for mocking keywords in unit tests.
28
+
29
+ ## Installation
30
+
31
+ ### Requirements
32
+
33
+ - Python 3.10 – 3.14
34
+ - Robot Framework 7.0 – 7.5
35
+
36
+ ### From PyPI (once published)
37
+
38
+ ```bash
39
+ pip install robotframework-mock
40
+ ```
41
+
42
+ ### From source
43
+
44
+ ```bash
45
+ git clone https://github.com/yourusername/robotframework-mock.git
46
+ cd robotframework-mock
47
+ pip install .
48
+ ```
49
+
50
+ ### For development
51
+
52
+ ```bash
53
+ pip install -e .
54
+ pip install -r requirements-dev.txt
55
+ ```
56
+
57
+ ## Features
58
+
59
+ - Mock keywords from any Robot Framework library
60
+ - Mock keywords from Robot Framework resource files
61
+ - Mock Robot Framework's BuiltIn keywords
62
+ - Support for keywords with custom names via @keyword decorator
63
+ - Verify keyword calls and call counts
64
+ - Measure resource-file keyword coverage with configurable thresholds
65
+ - Simple API with three main keywords
66
+
67
+ ## Usage
68
+
69
+ ### Mock Library Keywords
70
+
71
+ Import the library you want to mock, then create a MockLibrary instance for it:
72
+
73
+ ```robot
74
+ *** Settings ***
75
+ Library DatabaseLibrary
76
+ Library MockLibrary DatabaseLibrary WITH NAME MockDB
77
+
78
+ *** Test Cases ***
79
+ Test With Mocked Keyword
80
+ MockDB.Mock Keyword query return_value=test_data
81
+ ${result}= DatabaseLibrary.Query SELECT * FROM users
82
+ Should Be Equal ${result} test_data
83
+ MockDB.Reset Mocks
84
+ ```
85
+
86
+ ### Verify Calls
87
+
88
+ Verify that a keyword was called and optionally check the call count:
89
+
90
+ ```robot
91
+ *** Test Cases ***
92
+ Test Keyword Was Called
93
+ MockDB.Mock Keyword execute_sql return_value=${None}
94
+ Process User Registration
95
+ MockDB.Verify Keyword Called execute_sql times=1
96
+ MockDB.Reset Mocks
97
+ ```
98
+
99
+ ### Mock BuiltIn Keywords
100
+
101
+ Mock Robot Framework's built-in keywords using the same MockLibrary with "BuiltIn" as the library name:
102
+
103
+ ```robot
104
+ *** Settings ***
105
+ Library MockLibrary BuiltIn WITH NAME MockBin
106
+
107
+ *** Test Cases ***
108
+ Test BuiltIn Mock
109
+ MockBin.Mock Keyword Convert To Binary return_value=test_data
110
+ ${result}= Convert To Binary aaa
111
+ Should Be Equal ${result} test_data
112
+ MockBin.Reset Mocks
113
+ ```
114
+
115
+ ### Mock Multiple Libraries
116
+
117
+ You can mock multiple libraries in the same test:
118
+
119
+ ```robot
120
+ *** Settings ***
121
+ Library DatabaseLibrary
122
+ Library RequestsLibrary
123
+ Library MockLibrary DatabaseLibrary WITH NAME MockDB
124
+ Library MockLibrary RequestsLibrary WITH NAME MockReq
125
+
126
+ *** Test Cases ***
127
+ Test Multiple Mocks
128
+ MockDB.Mock Keyword query return_value=user_data
129
+ MockReq.Mock Keyword get return_value=api_response
130
+ # Your test code here
131
+ MockDB.Reset Mocks
132
+ MockReq.Reset Mocks
133
+ ```
134
+
135
+ ### Mock Resource Keywords
136
+
137
+ Mock keywords from Robot Framework resource files:
138
+
139
+ ```robot
140
+ *** Settings ***
141
+ Resource my_resource.robot
142
+ Library MockResource my_resource.robot WITH NAME MockRes
143
+
144
+ *** Test Cases ***
145
+ Test Resource Keyword Mock
146
+ MockRes.Mock Keyword My Custom Keyword return_value=mocked_value
147
+ ${result}= My Custom Keyword
148
+ Should Be Equal ${result} mocked_value
149
+ MockRes.Reset Mocks
150
+ ```
151
+
152
+ ## Keyword Coverage Measurement
153
+
154
+ `MockCoverage` measures how many of the keywords **defined** in your resource
155
+ files were actually **executed** by your tests — the Robot Framework analogue of
156
+ JaCoCo or coverage.py. Coverage requirements live in a TOML config file, and the
157
+ run fails if coverage falls below the configured threshold, so it can gate a CI
158
+ build.
159
+
160
+ Resource files are found by **recursively scanning directories** you list, so a
161
+ newly added resource file is measured automatically and cannot silently escape
162
+ the gate.
163
+
164
+ ### Coverage model
165
+
166
+ Coverage uses the same aggregate model as standard coverage tools: a keyword
167
+ counts as covered if it is executed **at any point during the run**, regardless
168
+ of which test triggered it. This includes keywords reached indirectly through
169
+ other keywords.
170
+
171
+ A discovered resource file whose keywords are never executed reports
172
+ **0% coverage** by design.
173
+
174
+ Keyword names are read from the resource files themselves; the config only
175
+ selects *which files* participate.
176
+
177
+ ### Configuration
178
+
179
+ Create a config file (e.g. `mock-coverage.toml`):
180
+
181
+ ```toml
182
+ [coverage]
183
+ # Global minimum coverage percentage across all discovered resources
184
+ fail_under = 80.0
185
+
186
+ # Directories scanned recursively for resource files
187
+ paths = [
188
+ "tests/core-common/resources",
189
+ "tests/core-ui/resources",
190
+ ]
191
+
192
+ # Which files to collect within those paths (default: ["*.resource"])
193
+ patterns = ["*.resource"]
194
+
195
+ # Optional exclusions, matched against the reported (relative) path
196
+ exclude = ["*deprecated*", "*/experimental/*"]
197
+
198
+ # Optional: stricter threshold for an individual file
199
+ [coverage.resources."tests/core-common/resources/vertica.resource"]
200
+ fail_under = 95.0
201
+ ```
202
+
203
+ | Key | Default | Description |
204
+ |---|---|---|
205
+ | `fail_under` | `0.0` | Minimum overall coverage percentage |
206
+ | `paths` | *(none)* | Directories scanned recursively |
207
+ | `patterns` | `["*.resource"]` | Filename patterns to collect |
208
+ | `exclude` | `[]` | Patterns to skip |
209
+ | `[coverage.resources."<file>"]` | — | Per-file threshold override |
210
+
211
+ Both the global total and each individual resource must meet its threshold for
212
+ the run to pass.
213
+
214
+ All paths are resolved **relative to the config file's own directory**, so the
215
+ same config works no matter which directory you invoke `robot` from. Absolute
216
+ paths are used as-is. A file listed explicitly under `[coverage.resources]` is
217
+ always measured, even if it lies outside `paths`.
218
+
219
+ ### Running
220
+
221
+ Enable it as a listener:
222
+
223
+ ```bash
224
+ robot --listener MockCoverage:config=mock-coverage.toml tests/
225
+ ```
226
+
227
+ Listener options are `name=value` pairs separated by colons:
228
+
229
+ | Option | Default | Description |
230
+ |---|---|---|
231
+ | `config` | `mock-coverage.toml` | Path to the TOML configuration file |
232
+ | `output` | `coverage.json` | JSON report path (directories are created) |
233
+ | `enforce` | `true` | Whether to fail the run when below threshold |
234
+ | `console` | `failing` | `failing` lists only breaches; `all` lists every resource |
235
+
236
+ ```bash
237
+ # Full table, reporting only (no build failure)
238
+ robot --listener MockCoverage:config=cov.toml:output=build/coverage.json:enforce=false:console=all tests/
239
+ ```
240
+
241
+ ### Output
242
+
243
+ By default the console report lists only the resources that are below their
244
+ threshold, which keeps output readable across large resource trees:
245
+
246
+ ```
247
+ Resource Keyword Coverage
248
+ Resources below threshold (1):
249
+ res/brand-new.resource 0/2 0.00% FAIL (>=50.0)
250
+ TOTAL 3/8 37.50% FAIL (>=50.0) [4 resources]
251
+ ```
252
+
253
+ With `console=all`, every measured resource is listed:
254
+
255
+ ```
256
+ Resource Keyword Coverage
257
+ res/deep/nested/util.resource 1/2 50.00% PASS (>=50.0)
258
+ res/x/common.resource 1/2 50.00% PASS (>=50.0)
259
+ res/y/common.resource 1/2 50.00% PASS (>=50.0)
260
+ TOTAL 3/6 50.00% PASS (>=50.0) [3 resources]
261
+ ```
262
+
263
+ When coverage is below threshold and `enforce` is enabled, the process exits with
264
+ a non-zero status **even if all tests passed**, failing the build.
265
+
266
+ A machine-readable JSON report is always written with the full per-file detail,
267
+ naming exactly which keywords were covered and which were missed:
268
+
269
+ ```json
270
+ {
271
+ "total": {
272
+ "resources": 1,
273
+ "defined": 4,
274
+ "covered": 3,
275
+ "percent": 75.0,
276
+ "fail_under": 75.0,
277
+ "passed": true
278
+ },
279
+ "resources": [
280
+ {
281
+ "path": "resources/coverage-demo.resource",
282
+ "defined": 4,
283
+ "covered": 3,
284
+ "percent": 75.0,
285
+ "fail_under": 75.0,
286
+ "passed": true,
287
+ "covered_keywords": ["Covered Keyword One", "Covered Keyword Three", "Covered Keyword Two"],
288
+ "missed_keywords": ["Uncovered Keyword"]
289
+ }
290
+ ]
291
+ }
292
+ ```
293
+
294
+ ### Notes and limitations
295
+
296
+ - Executed keywords are attributed to their **real source file**, resolved
297
+ through Robot Framework's namespace at call time. Resource files sharing the
298
+ same base name in different directories are measured independently.
299
+ - Coverage is measured at **keyword granularity** (was this keyword executed?),
300
+ not at line or branch level.
301
+ - Python library keywords are not measured — use `pytest` with `coverage.py` for
302
+ those.
303
+ - TOML parsing uses the stdlib `tomllib` on Python 3.11+; on older versions the
304
+ `tomli` backport is installed automatically as a dependency.
305
+
306
+ ## Keywords
307
+
308
+ ### Mock Keyword
309
+
310
+ Mock a keyword with a return value or side effect.
311
+
312
+ **Arguments:**
313
+ - `keyword_name` - Name of the keyword to mock
314
+ - `return_value` - Value to return when called (optional)
315
+ - `side_effect` - Callable to execute instead (optional)
316
+
317
+ **Example:**
318
+ ```robot
319
+ MockDB.Mock Keyword query return_value=test_data
320
+ ```
321
+
322
+ ### Reset Mocks
323
+
324
+ Restore all mocked keywords to their original implementations.
325
+
326
+ **Example:**
327
+ ```robot
328
+ MockDB.Reset Mocks
329
+ ```
330
+
331
+ ### Verify Keyword Called
332
+
333
+ Verify a keyword was called, optionally checking call count.
334
+
335
+ **Arguments:**
336
+ - `keyword_name` - Name of the keyword to verify
337
+ - `times` - Expected number of calls (optional)
338
+
339
+ **Example:**
340
+ ```robot
341
+ MockDB.Verify Keyword Called execute_sql times=1
342
+ ```
343
+
344
+ ## How It Works
345
+
346
+ ### MockLibrary
347
+
348
+ MockLibrary dynamically replaces keyword implementations:
349
+ 1. Wraps the target library instance
350
+ 2. Resolves keyword names to function names (handles @keyword decorator)
351
+ 3. Stores original methods before mocking
352
+ 4. Replaces methods with mock implementations using Python's unittest.mock.Mock
353
+ 5. Returns mocked values or executes side effects
354
+ 6. Tracks call counts for verification
355
+ 7. Raises AttributeError if attempting to mock a non-existent keyword
356
+
357
+ ### MockResource
358
+
359
+ MockResource patches Robot Framework's keyword execution:
360
+ 1. Patches the Namespace.get_runner method
361
+ 2. Intercepts keyword execution for the specified resource file
362
+ 3. Replaces keyword body with Return statement containing mocked value
363
+ 4. Tracks call counts for verification
364
+ 5. Restores original keyword body on reset
365
+
366
+ ### MockCoverage
367
+
368
+ MockCoverage measures resource keyword coverage as a listener:
369
+ 1. Reads thresholds and scan paths from the TOML config file
370
+ 2. Recursively discovers resource files under those paths
371
+ 3. Parses each one with Robot Framework's own parsing API to enumerate the
372
+ keywords it defines
373
+ 4. Records executed keywords via the `start_keyword` listener event, resolving
374
+ each keyword's real source file through Robot's namespace so same-named
375
+ resources stay distinct
376
+ 5. Computes per-resource and total coverage percentages at the end of the run
377
+ 6. Writes a JSON report and prints a summary table
378
+ 7. Exits non-zero if any threshold is unmet and enforcement is enabled
379
+
380
+ ## Notes
381
+
382
+ - Both libraries use `ROBOT_LIBRARY_SCOPE = 'GLOBAL'` to maintain state across test cases
383
+ - Built on Python's unittest.mock.Mock for robust mocking capabilities
384
+ - MockLibrary supports any Robot Framework library, including BuiltIn
385
+ - MockResource works with resource files by patching the keyword execution pipeline
386
+
387
+ ## License
388
+
389
+ See LICENSE file for details.