robotframework-mock 0.3.0__tar.gz → 0.5.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.
Files changed (20) hide show
  1. robotframework_mock-0.5.0/PKG-INFO +454 -0
  2. robotframework_mock-0.5.0/README.md +430 -0
  3. {robotframework_mock-0.3.0 → robotframework_mock-0.5.0}/setup.cfg +8 -2
  4. robotframework_mock-0.5.0/src/MockCoverage/__init__.py +735 -0
  5. {robotframework_mock-0.3.0 → robotframework_mock-0.5.0}/src/MockLibrary/__init__.py +17 -1
  6. {robotframework_mock-0.3.0 → robotframework_mock-0.5.0}/src/MockResource/__init__.py +57 -4
  7. robotframework_mock-0.5.0/src/_mock_core/__init__.py +180 -0
  8. robotframework_mock-0.5.0/src/robotframework_mock.egg-info/PKG-INFO +454 -0
  9. {robotframework_mock-0.3.0 → robotframework_mock-0.5.0}/src/robotframework_mock.egg-info/SOURCES.txt +2 -0
  10. robotframework_mock-0.5.0/src/robotframework_mock.egg-info/requires.txt +4 -0
  11. {robotframework_mock-0.3.0 → robotframework_mock-0.5.0}/src/robotframework_mock.egg-info/top_level.txt +2 -0
  12. robotframework_mock-0.3.0/PKG-INFO +0 -209
  13. robotframework_mock-0.3.0/README.md +0 -191
  14. robotframework_mock-0.3.0/src/robotframework_mock.egg-info/PKG-INFO +0 -209
  15. robotframework_mock-0.3.0/src/robotframework_mock.egg-info/requires.txt +0 -1
  16. {robotframework_mock-0.3.0 → robotframework_mock-0.5.0}/LICENSE +0 -0
  17. {robotframework_mock-0.3.0 → robotframework_mock-0.5.0}/MANIFEST.in +0 -0
  18. {robotframework_mock-0.3.0 → robotframework_mock-0.5.0}/pyproject.toml +0 -0
  19. {robotframework_mock-0.3.0 → robotframework_mock-0.5.0}/setup.py +0 -0
  20. {robotframework_mock-0.3.0 → robotframework_mock-0.5.0}/src/robotframework_mock.egg-info/dependency_links.txt +0 -0
@@ -0,0 +1,454 @@
1
+ Metadata-Version: 2.4
2
+ Name: robotframework-mock
3
+ Version: 0.5.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
+ - Inspect and verify the arguments a mocked keyword was called with
65
+ - Measure resource-file keyword coverage with configurable thresholds
66
+ - Simple API with three main keywords
67
+
68
+ ## Usage
69
+
70
+ ### Mock Library Keywords
71
+
72
+ Import the library you want to mock, then create a MockLibrary instance for it:
73
+
74
+ ```robot
75
+ *** Settings ***
76
+ Library DatabaseLibrary
77
+ Library MockLibrary DatabaseLibrary WITH NAME MockDB
78
+
79
+ *** Test Cases ***
80
+ Test With Mocked Keyword
81
+ MockDB.Mock Keyword query return_value=test_data
82
+ ${result}= DatabaseLibrary.Query SELECT * FROM users
83
+ Should Be Equal ${result} test_data
84
+ MockDB.Reset Mocks
85
+ ```
86
+
87
+ ### Verify Calls
88
+
89
+ Verify that a keyword was called and optionally check the call count:
90
+
91
+ ```robot
92
+ *** Test Cases ***
93
+ Test Keyword Was Called
94
+ MockDB.Mock Keyword execute_sql return_value=${None}
95
+ Process User Registration
96
+ MockDB.Verify Keyword Called execute_sql times=1
97
+ MockDB.Reset Mocks
98
+ ```
99
+
100
+ ### Mock BuiltIn Keywords
101
+
102
+ Mock Robot Framework's built-in keywords using the same MockLibrary with "BuiltIn" as the library name:
103
+
104
+ ```robot
105
+ *** Settings ***
106
+ Library MockLibrary BuiltIn WITH NAME MockBin
107
+
108
+ *** Test Cases ***
109
+ Test BuiltIn Mock
110
+ MockBin.Mock Keyword Convert To Binary return_value=test_data
111
+ ${result}= Convert To Binary aaa
112
+ Should Be Equal ${result} test_data
113
+ MockBin.Reset Mocks
114
+ ```
115
+
116
+ ### Mock Multiple Libraries
117
+
118
+ You can mock multiple libraries in the same test:
119
+
120
+ ```robot
121
+ *** Settings ***
122
+ Library DatabaseLibrary
123
+ Library RequestsLibrary
124
+ Library MockLibrary DatabaseLibrary WITH NAME MockDB
125
+ Library MockLibrary RequestsLibrary WITH NAME MockReq
126
+
127
+ *** Test Cases ***
128
+ Test Multiple Mocks
129
+ MockDB.Mock Keyword query return_value=user_data
130
+ MockReq.Mock Keyword get return_value=api_response
131
+ # Your test code here
132
+ MockDB.Reset Mocks
133
+ MockReq.Reset Mocks
134
+ ```
135
+
136
+ ### Mock Resource Keywords
137
+
138
+ Mock keywords from Robot Framework resource files:
139
+
140
+ ```robot
141
+ *** Settings ***
142
+ Resource my_resource.robot
143
+ Library MockResource my_resource.robot WITH NAME MockRes
144
+
145
+ *** Test Cases ***
146
+ Test Resource Keyword Mock
147
+ MockRes.Mock Keyword My Custom Keyword return_value=mocked_value
148
+ ${result}= My Custom Keyword
149
+ Should Be Equal ${result} mocked_value
150
+ MockRes.Reset Mocks
151
+ ```
152
+
153
+ ## Keyword Coverage Measurement
154
+
155
+ `MockCoverage` measures how many of the keywords **defined** in your resource
156
+ files were actually **executed** by your tests — the Robot Framework analogue of
157
+ JaCoCo or coverage.py. Coverage requirements live in a TOML config file, and the
158
+ run fails if coverage falls below the configured threshold, so it can gate a CI
159
+ build.
160
+
161
+ Resource files are found by **recursively scanning directories** you list, so a
162
+ newly added resource file is measured automatically and cannot silently escape
163
+ the gate.
164
+
165
+ ### Coverage model
166
+
167
+ Coverage uses the same aggregate model as standard coverage tools: a keyword
168
+ counts as covered if it is executed **at any point during the run**, regardless
169
+ of which test triggered it. This includes keywords reached indirectly through
170
+ other keywords.
171
+
172
+ A discovered resource file whose keywords are never executed reports
173
+ **0% coverage** by design.
174
+
175
+ Keyword names are read from the resource files themselves; the config only
176
+ selects *which files* participate.
177
+
178
+ ### Configuration
179
+
180
+ Create a config file (e.g. `mock-coverage.toml`):
181
+
182
+ ```toml
183
+ [coverage]
184
+ # Global minimum coverage percentage across all discovered resources
185
+ fail_under = 80.0
186
+
187
+ # Directories scanned recursively for resource files
188
+ paths = [
189
+ "tests/core-common/resources",
190
+ "tests/core-ui/resources",
191
+ ]
192
+
193
+ # Which files to collect within those paths (default: ["*.resource"])
194
+ patterns = ["*.resource"]
195
+
196
+ # Optional exclusions, matched against the reported (relative) path
197
+ exclude = ["*deprecated*", "*/experimental/*"]
198
+
199
+ # Optional: stricter threshold for an individual file
200
+ [coverage.resources."tests/core-common/resources/vertica.resource"]
201
+ fail_under = 95.0
202
+ ```
203
+
204
+ | Key | Default | Description |
205
+ |---|---|---|
206
+ | `fail_under` | `0.0` | Minimum overall coverage percentage |
207
+ | `paths` | *(none)* | Directories scanned recursively |
208
+ | `patterns` | `["*.resource"]` | Filename patterns to collect |
209
+ | `exclude` | `[]` | Patterns to skip |
210
+ | `[coverage.resources."<file>"]` | — | Per-file threshold override |
211
+
212
+ Both the global total and each individual resource must meet its threshold for
213
+ the run to pass.
214
+
215
+ All paths are resolved **relative to the config file's own directory**, so the
216
+ same config works no matter which directory you invoke `robot` from. Absolute
217
+ paths are used as-is. A file listed explicitly under `[coverage.resources]` is
218
+ always measured, even if it lies outside `paths`.
219
+
220
+ ### Running
221
+
222
+ Enable it as a listener:
223
+
224
+ ```bash
225
+ robot --listener MockCoverage:config=mock-coverage.toml tests/
226
+ ```
227
+
228
+ Listener options are `name=value` pairs separated by colons:
229
+
230
+ | Option | Default | Description |
231
+ |---|---|---|
232
+ | `config` | `mock-coverage.toml` | Path to the TOML configuration file |
233
+ | `output` | `coverage.json` | JSON report path (directories are created) |
234
+ | `enforce` | `true` | Whether to fail the run when below threshold |
235
+ | `console` | `failing` | `failing` lists only breaches; `all` lists every resource |
236
+
237
+ ```bash
238
+ # Full table, reporting only (no build failure)
239
+ robot --listener MockCoverage:config=cov.toml:output=build/coverage.json:enforce=false:console=all tests/
240
+ ```
241
+
242
+ ### Output
243
+
244
+ By default the console report lists only the resources that are below their
245
+ threshold, which keeps output readable across large resource trees:
246
+
247
+ ```
248
+ Resource Keyword Coverage
249
+ Resources below threshold (1):
250
+ res/brand-new.resource 0/2 0.00% FAIL (>=50.0)
251
+ TOTAL 3/8 37.50% FAIL (>=50.0) [4 resources]
252
+ ```
253
+
254
+ With `console=all`, every measured resource is listed:
255
+
256
+ ```
257
+ Resource Keyword Coverage
258
+ res/deep/nested/util.resource 1/2 50.00% PASS (>=50.0)
259
+ res/x/common.resource 1/2 50.00% PASS (>=50.0)
260
+ res/y/common.resource 1/2 50.00% PASS (>=50.0)
261
+ TOTAL 3/6 50.00% PASS (>=50.0) [3 resources]
262
+ ```
263
+
264
+ When coverage is below threshold and `enforce` is enabled, the process exits with
265
+ a non-zero status **even if all tests passed**, failing the build.
266
+
267
+ A machine-readable JSON report is always written with the full per-file detail,
268
+ naming exactly which keywords were covered and which were missed:
269
+
270
+ ```json
271
+ {
272
+ "total": {
273
+ "resources": 1,
274
+ "defined": 4,
275
+ "covered": 3,
276
+ "percent": 75.0,
277
+ "fail_under": 75.0,
278
+ "passed": true
279
+ },
280
+ "resources": [
281
+ {
282
+ "path": "resources/coverage-demo.resource",
283
+ "defined": 4,
284
+ "covered": 3,
285
+ "percent": 75.0,
286
+ "fail_under": 75.0,
287
+ "passed": true,
288
+ "covered_keywords": ["Covered Keyword One", "Covered Keyword Three", "Covered Keyword Two"],
289
+ "missed_keywords": ["Uncovered Keyword"]
290
+ }
291
+ ]
292
+ }
293
+ ```
294
+
295
+ ### Notes and limitations
296
+
297
+ - Executed keywords are attributed to their **real source file**, resolved
298
+ through Robot Framework's namespace at call time. Resource files sharing the
299
+ same base name in different directories are measured independently.
300
+ - Coverage is measured at **keyword granularity** (was this keyword executed?),
301
+ not at line or branch level.
302
+ - Python library keywords are not measured — use `pytest` with `coverage.py` for
303
+ those.
304
+ - TOML parsing uses the stdlib `tomllib` on Python 3.11+; on older versions the
305
+ `tomli` backport is installed automatically as a dependency.
306
+
307
+ ## Keywords
308
+
309
+ ### Mock Keyword
310
+
311
+ Mock a keyword with a return value or side effect.
312
+
313
+ **Arguments:**
314
+ - `keyword_name` - Name of the keyword to mock
315
+ - `return_value` - Value to return when called (optional)
316
+ - `side_effect` - Callable to execute instead (optional)
317
+
318
+ **Example:**
319
+ ```robot
320
+ MockDB.Mock Keyword query return_value=test_data
321
+ ```
322
+
323
+ ### Reset Mocks
324
+
325
+ Restore all mocked keywords to their original implementations.
326
+
327
+ **Example:**
328
+ ```robot
329
+ MockDB.Reset Mocks
330
+ ```
331
+
332
+ ### Verify Keyword Called
333
+
334
+ Verify a keyword was called, optionally checking call count.
335
+
336
+ **Arguments:**
337
+ - `keyword_name` - Name of the keyword to verify
338
+ - `times` - Expected number of calls (optional)
339
+
340
+ **Example:**
341
+ ```robot
342
+ MockDB.Verify Keyword Called execute_sql times=1
343
+ ```
344
+
345
+ ### Verify Keyword Called With
346
+
347
+ Verify a keyword was called with the given arguments. Passes when **at least one**
348
+ recorded call matches, so the order of calls does not matter.
349
+
350
+ **Arguments:**
351
+ - `keyword_name` - Name of the keyword to verify
352
+ - `*args` - Expected positional arguments
353
+ - `**kwargs` - Expected named arguments
354
+
355
+ **Example:**
356
+ ```robot
357
+ MockDB.Verify Keyword Called With execute_sql SELECT 1 timeout=${30}
358
+ ```
359
+
360
+ Arguments are compared with Python equality, so types matter. Values are
361
+ recorded exactly as Robot Framework passed them to the keyword: test data is
362
+ string data, but Robot converts arguments of keywords that declare argument
363
+ types, and which built-in keywords declare types differs between Robot
364
+ Framework versions. When a recorded value is therefore not a string, give the
365
+ expectation as a typed Robot variable (`timeout=${30}` rather than
366
+ `timeout=30`), or read the call back with `Get Keyword Call Kwargs` and assert
367
+ on it with a type-insensitive comparison.
368
+
369
+ ### Get Keyword Call Args
370
+
371
+ Return the positional arguments of one call to a mocked keyword.
372
+
373
+ **Arguments:**
374
+ - `keyword_name` - Name of the mocked keyword
375
+ - `index` - Zero-based call index, negative counts from the end (default `0`)
376
+
377
+ **Example:**
378
+ ```robot
379
+ ${args}= MockDB.Get Keyword Call Args execute_sql index=0
380
+ Should Be Equal ${args}[0] SELECT 1
381
+ ```
382
+
383
+ ### Get Keyword Call Kwargs
384
+
385
+ Return the named arguments of one call to a mocked keyword.
386
+
387
+ **Arguments:**
388
+ - `keyword_name` - Name of the mocked keyword
389
+ - `index` - Zero-based call index, negative counts from the end (default `0`)
390
+
391
+ **Example:**
392
+ ```robot
393
+ ${kwargs}= MockDB.Get Keyword Call Kwargs execute_sql
394
+ Should Be Equal ${kwargs}[timeout] ${30}
395
+ ```
396
+
397
+ ### Get Keyword Call Count
398
+
399
+ Return how many times a mocked keyword was called.
400
+
401
+ **Example:**
402
+ ```robot
403
+ ${count}= MockDB.Get Keyword Call Count execute_sql
404
+ ```
405
+
406
+ ## How It Works
407
+
408
+ ### MockLibrary
409
+
410
+ MockLibrary dynamically replaces keyword implementations:
411
+ 1. Wraps the target library instance
412
+ 2. Resolves keyword names to function names (handles @keyword decorator)
413
+ 3. Stores original methods before mocking
414
+ 4. Replaces methods with mock implementations using Python's unittest.mock.Mock
415
+ 5. Returns mocked values or executes side effects
416
+ 6. Tracks call counts for verification
417
+ 7. Raises AttributeError if attempting to mock a non-existent keyword
418
+
419
+ ### MockResource
420
+
421
+ MockResource patches Robot Framework's keyword execution:
422
+ 1. Patches the Namespace.get_runner method
423
+ 2. Intercepts keyword execution for the specified resource file
424
+ 3. Resolves the call's arguments - variables are replaced, and a `name=value`
425
+ argument becomes a named argument when the keyword declares that name - so
426
+ mocks record what the keyword was really called with
427
+ 4. Replaces keyword body with Return statement containing mocked value
428
+ 5. Tracks call counts and call arguments for verification
429
+ 6. Restores original keyword body on reset
430
+
431
+ ### MockCoverage
432
+
433
+ MockCoverage measures resource keyword coverage as a listener:
434
+ 1. Reads thresholds and scan paths from the TOML config file
435
+ 2. Recursively discovers resource files under those paths
436
+ 3. Parses each one with Robot Framework's own parsing API to enumerate the
437
+ keywords it defines
438
+ 4. Records executed keywords via the `start_keyword` listener event, resolving
439
+ each keyword's real source file through Robot's namespace so same-named
440
+ resources stay distinct
441
+ 5. Computes per-resource and total coverage percentages at the end of the run
442
+ 6. Writes a JSON report and prints a summary table
443
+ 7. Exits non-zero if any threshold is unmet and enforcement is enabled
444
+
445
+ ## Notes
446
+
447
+ - Both libraries use `ROBOT_LIBRARY_SCOPE = 'GLOBAL'` to maintain state across test cases
448
+ - Built on Python's unittest.mock.Mock for robust mocking capabilities
449
+ - MockLibrary supports any Robot Framework library, including BuiltIn
450
+ - MockResource works with resource files by patching the keyword execution pipeline
451
+
452
+ ## License
453
+
454
+ See LICENSE file for details.