@mytechtoday/augment-extensions 0.2.0 → 0.4.0
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.
- package/README.md +614 -39
- package/augment-extensions/coding-standards/bash/README.md +196 -0
- package/augment-extensions/coding-standards/bash/module.json +163 -0
- package/augment-extensions/coding-standards/bash/rules/naming-conventions.md +336 -0
- package/augment-extensions/coding-standards/bash/rules/universal-standards.md +289 -0
- package/augment-extensions/coding-standards/css/README.md +40 -0
- package/augment-extensions/coding-standards/css/examples/css-examples.css +550 -0
- package/augment-extensions/coding-standards/css/module.json +44 -0
- package/augment-extensions/coding-standards/css/rules/css-modern-features.md +448 -0
- package/augment-extensions/coding-standards/css/rules/css-standards.md +492 -0
- package/augment-extensions/coding-standards/html/README.md +40 -0
- package/augment-extensions/coding-standards/html/examples/html-examples.html +267 -0
- package/augment-extensions/coding-standards/html/examples/responsive-layout.html +505 -0
- package/augment-extensions/coding-standards/html/module.json +44 -0
- package/augment-extensions/coding-standards/html/rules/html-standards.md +349 -0
- package/augment-extensions/coding-standards/html-css-js/README.md +194 -0
- package/augment-extensions/coding-standards/html-css-js/examples/async-examples.js +487 -0
- package/augment-extensions/coding-standards/html-css-js/examples/css-examples.css +550 -0
- package/augment-extensions/coding-standards/html-css-js/examples/dom-examples.js +667 -0
- package/augment-extensions/coding-standards/html-css-js/examples/html-examples.html +267 -0
- package/augment-extensions/coding-standards/html-css-js/examples/javascript-examples.js +612 -0
- package/augment-extensions/coding-standards/html-css-js/examples/responsive-layout.html +505 -0
- package/augment-extensions/coding-standards/html-css-js/module.json +48 -0
- package/augment-extensions/coding-standards/html-css-js/rules/async-patterns.md +515 -0
- package/augment-extensions/coding-standards/html-css-js/rules/css-modern-features.md +448 -0
- package/augment-extensions/coding-standards/html-css-js/rules/css-standards.md +492 -0
- package/augment-extensions/coding-standards/html-css-js/rules/dom-manipulation.md +439 -0
- package/augment-extensions/coding-standards/html-css-js/rules/html-standards.md +349 -0
- package/augment-extensions/coding-standards/html-css-js/rules/javascript-standards.md +486 -0
- package/augment-extensions/coding-standards/html-css-js/rules/performance.md +463 -0
- package/augment-extensions/coding-standards/html-css-js/rules/tooling.md +543 -0
- package/augment-extensions/coding-standards/js/README.md +46 -0
- package/augment-extensions/coding-standards/js/examples/async-examples.js +487 -0
- package/augment-extensions/coding-standards/js/examples/dom-examples.js +667 -0
- package/augment-extensions/coding-standards/js/examples/javascript-examples.js +612 -0
- package/augment-extensions/coding-standards/js/module.json +49 -0
- package/augment-extensions/coding-standards/js/rules/async-patterns.md +515 -0
- package/augment-extensions/coding-standards/js/rules/dom-manipulation.md +439 -0
- package/augment-extensions/coding-standards/js/rules/javascript-standards.md +486 -0
- package/augment-extensions/coding-standards/js/rules/performance.md +463 -0
- package/augment-extensions/coding-standards/js/rules/tooling.md +543 -0
- package/augment-extensions/coding-standards/php/README.md +248 -0
- package/augment-extensions/coding-standards/php/examples/api-endpoint-example.php +204 -0
- package/augment-extensions/coding-standards/php/examples/cli-command-example.php +206 -0
- package/augment-extensions/coding-standards/php/examples/legacy-refactoring-example.php +234 -0
- package/augment-extensions/coding-standards/php/examples/web-application-example.php +211 -0
- package/augment-extensions/coding-standards/php/examples/woocommerce-extension-example.php +215 -0
- package/augment-extensions/coding-standards/php/examples/wordpress-plugin-example.php +189 -0
- package/augment-extensions/coding-standards/php/module.json +166 -0
- package/augment-extensions/coding-standards/php/rules/api-development.md +480 -0
- package/augment-extensions/coding-standards/php/rules/category-configuration.md +332 -0
- package/augment-extensions/coding-standards/php/rules/cli-tools.md +472 -0
- package/augment-extensions/coding-standards/php/rules/cms-integration.md +561 -0
- package/augment-extensions/coding-standards/php/rules/code-quality.md +402 -0
- package/augment-extensions/coding-standards/php/rules/documentation.md +425 -0
- package/augment-extensions/coding-standards/php/rules/ecommerce.md +627 -0
- package/augment-extensions/coding-standards/php/rules/error-handling.md +336 -0
- package/augment-extensions/coding-standards/php/rules/legacy-migration.md +677 -0
- package/augment-extensions/coding-standards/php/rules/naming-conventions.md +279 -0
- package/augment-extensions/coding-standards/php/rules/performance.md +392 -0
- package/augment-extensions/coding-standards/php/rules/psr-standards.md +186 -0
- package/augment-extensions/coding-standards/php/rules/security.md +358 -0
- package/augment-extensions/coding-standards/php/rules/testing.md +403 -0
- package/augment-extensions/coding-standards/php/rules/type-declarations.md +331 -0
- package/augment-extensions/coding-standards/php/rules/web-applications.md +426 -0
- package/augment-extensions/coding-standards/powershell/README.md +154 -0
- package/augment-extensions/coding-standards/powershell/examples/admin-example.ps1 +272 -0
- package/augment-extensions/coding-standards/powershell/examples/automation-example.ps1 +173 -0
- package/augment-extensions/coding-standards/powershell/examples/cloud-example.ps1 +243 -0
- package/augment-extensions/coding-standards/powershell/examples/cross-platform-example.ps1 +297 -0
- package/augment-extensions/coding-standards/powershell/examples/dsc-example.ps1 +224 -0
- package/augment-extensions/coding-standards/powershell/examples/legacy-migration-example.ps1 +340 -0
- package/augment-extensions/coding-standards/powershell/examples/module-example.psm1 +255 -0
- package/augment-extensions/coding-standards/powershell/module.json +165 -0
- package/augment-extensions/coding-standards/powershell/rules/administrative-tools.md +439 -0
- package/augment-extensions/coding-standards/powershell/rules/automation-scripts.md +240 -0
- package/augment-extensions/coding-standards/powershell/rules/cloud-orchestration.md +384 -0
- package/augment-extensions/coding-standards/powershell/rules/configuration-schema.md +383 -0
- package/augment-extensions/coding-standards/powershell/rules/cross-platform-scripts.md +482 -0
- package/augment-extensions/coding-standards/powershell/rules/dsc-configurations.md +296 -0
- package/augment-extensions/coding-standards/powershell/rules/error-handling.md +314 -0
- package/augment-extensions/coding-standards/powershell/rules/legacy-migrations.md +466 -0
- package/augment-extensions/coding-standards/powershell/rules/modules-functions.md +244 -0
- package/augment-extensions/coding-standards/powershell/rules/naming-conventions.md +266 -0
- package/augment-extensions/coding-standards/powershell/rules/performance-optimization.md +209 -0
- package/augment-extensions/coding-standards/powershell/rules/security-practices.md +314 -0
- package/augment-extensions/coding-standards/powershell/rules/testing-guidelines.md +268 -0
- package/augment-extensions/coding-standards/powershell/rules/universal-standards.md +197 -0
- package/augment-extensions/coding-standards/python/README.md +12 -8
- package/augment-extensions/coding-standards/python/examples/best-practices.py +373 -0
- package/augment-extensions/coding-standards/python/module.json +8 -4
- package/augment-extensions/coding-standards/python/rules/async-patterns.md +884 -0
- package/augment-extensions/coding-standards/python/rules/documentation.md +831 -0
- package/augment-extensions/coding-standards/python/rules/error-handling.md +855 -68
- package/augment-extensions/coding-standards/python/rules/testing.md +409 -0
- package/augment-extensions/coding-standards/python/rules/tooling.md +446 -0
- package/augment-extensions/coding-standards/python/rules/type-hints.md +115 -50
- package/augment-extensions/collections/html-css-js/README.md +82 -0
- package/augment-extensions/collections/html-css-js/collection.json +41 -0
- package/augment-extensions/domain-rules/database/README.md +161 -0
- package/augment-extensions/domain-rules/database/examples/flat-database-example.md +793 -0
- package/augment-extensions/domain-rules/database/examples/hybrid-database-example.md +1132 -0
- package/augment-extensions/domain-rules/database/examples/nosql-document-example.md +868 -0
- package/augment-extensions/domain-rules/database/examples/nosql-graph-example.md +805 -0
- package/augment-extensions/domain-rules/database/examples/relational-schema-example.md +621 -0
- package/augment-extensions/domain-rules/database/examples/vector-database-example.md +965 -0
- package/augment-extensions/domain-rules/database/module.json +28 -0
- package/augment-extensions/domain-rules/database/rules/flat-databases.md +624 -0
- package/augment-extensions/domain-rules/database/rules/nosql-databases.md +588 -0
- package/augment-extensions/domain-rules/database/rules/nosql-document-stores.md +856 -0
- package/augment-extensions/domain-rules/database/rules/nosql-graph-databases.md +778 -0
- package/augment-extensions/domain-rules/database/rules/nosql-key-value-stores.md +963 -0
- package/augment-extensions/domain-rules/database/rules/performance-optimization.md +1076 -0
- package/augment-extensions/domain-rules/database/rules/relational-databases.md +697 -0
- package/augment-extensions/domain-rules/database/rules/relational-indexing.md +671 -0
- package/augment-extensions/domain-rules/database/rules/relational-query-optimization.md +607 -0
- package/augment-extensions/domain-rules/database/rules/relational-schema-design.md +907 -0
- package/augment-extensions/domain-rules/database/rules/relational-transactions.md +783 -0
- package/augment-extensions/domain-rules/database/rules/security-standards.md +980 -0
- package/augment-extensions/domain-rules/database/rules/universal-best-practices.md +485 -0
- package/augment-extensions/domain-rules/database/rules/vector-databases.md +521 -0
- package/augment-extensions/domain-rules/database/rules/vector-embeddings.md +858 -0
- package/augment-extensions/domain-rules/database/rules/vector-indexing.md +934 -0
- package/augment-extensions/domain-rules/mcp/README.md +150 -0
- package/augment-extensions/domain-rules/mcp/examples/compressed-example.md +522 -0
- package/augment-extensions/domain-rules/mcp/examples/graph-augmented-example.md +520 -0
- package/augment-extensions/domain-rules/mcp/examples/hybrid-example.md +570 -0
- package/augment-extensions/domain-rules/mcp/examples/state-based-example.md +427 -0
- package/augment-extensions/domain-rules/mcp/examples/token-based-example.md +435 -0
- package/augment-extensions/domain-rules/mcp/examples/vector-based-example.md +502 -0
- package/augment-extensions/domain-rules/mcp/module.json +49 -0
- package/augment-extensions/domain-rules/mcp/rules/compressed-mcp.md +595 -0
- package/augment-extensions/domain-rules/mcp/rules/configuration.md +345 -0
- package/augment-extensions/domain-rules/mcp/rules/graph-augmented-mcp.md +687 -0
- package/augment-extensions/domain-rules/mcp/rules/hybrid-mcp.md +636 -0
- package/augment-extensions/domain-rules/mcp/rules/state-based-mcp.md +484 -0
- package/augment-extensions/domain-rules/mcp/rules/testing-validation.md +360 -0
- package/augment-extensions/domain-rules/mcp/rules/token-based-mcp.md +393 -0
- package/augment-extensions/domain-rules/mcp/rules/universal-rules.md +194 -0
- package/augment-extensions/domain-rules/mcp/rules/vector-based-mcp.md +625 -0
- package/augment-extensions/workflows/beads/module.json +4 -3
- package/augment-extensions/workflows/database/README.md +195 -0
- package/augment-extensions/workflows/database/ai-prompt-testing.md +295 -0
- package/augment-extensions/workflows/database/examples/migration-example.md +498 -0
- package/augment-extensions/workflows/database/examples/optimization-example.md +496 -0
- package/augment-extensions/workflows/database/examples/schema-design-example.md +444 -0
- package/augment-extensions/workflows/database/module.json +42 -0
- package/augment-extensions/workflows/database/rules/data-migration.md +249 -0
- package/augment-extensions/workflows/database/rules/documentation-standards.md +339 -0
- package/augment-extensions/workflows/database/rules/migration-workflow.md +352 -0
- package/augment-extensions/workflows/database/rules/optimization-workflow.md +435 -0
- package/augment-extensions/workflows/database/rules/schema-design-workflow.md +535 -0
- package/augment-extensions/workflows/database/rules/testing-patterns.md +305 -0
- package/augment-extensions/workflows/database/rules/workflow.md +458 -0
- package/augment-extensions/workflows/openspec/module.json +4 -3
- package/augment-extensions/writing-standards/screenplay/README.md +171 -0
- package/augment-extensions/writing-standards/screenplay/examples/aaa-hollywood-scene.fountain +164 -0
- package/augment-extensions/writing-standards/screenplay/module.json +124 -0
- package/augment-extensions/writing-standards/screenplay/rules/universal-formatting.md +339 -0
- package/cli/MODULES.md +302 -0
- package/cli/dist/cli.js +142 -9
- package/cli/dist/cli.js.map +1 -1
- package/cli/dist/commands/catalog.d.ts +13 -0
- package/cli/dist/commands/catalog.d.ts.map +1 -0
- package/cli/dist/commands/catalog.js +104 -0
- package/cli/dist/commands/catalog.js.map +1 -0
- package/cli/dist/commands/gui.d.ts +6 -0
- package/cli/dist/commands/gui.d.ts.map +1 -0
- package/cli/dist/commands/gui.js +211 -0
- package/cli/dist/commands/gui.js.map +1 -0
- package/cli/dist/commands/init.d.ts.map +1 -1
- package/cli/dist/commands/init.js +12 -0
- package/cli/dist/commands/init.js.map +1 -1
- package/cli/dist/commands/install-rules.d.ts +14 -0
- package/cli/dist/commands/install-rules.d.ts.map +1 -0
- package/cli/dist/commands/install-rules.js +127 -0
- package/cli/dist/commands/install-rules.js.map +1 -0
- package/cli/dist/commands/link.d.ts.map +1 -1
- package/cli/dist/commands/link.js +9 -11
- package/cli/dist/commands/link.js.map +1 -1
- package/cli/dist/commands/list.d.ts.map +1 -1
- package/cli/dist/commands/list.js +11 -28
- package/cli/dist/commands/list.js.map +1 -1
- package/cli/dist/commands/mcp.d.ts +48 -0
- package/cli/dist/commands/mcp.d.ts.map +1 -0
- package/cli/dist/commands/mcp.js +229 -0
- package/cli/dist/commands/mcp.js.map +1 -0
- package/cli/dist/commands/self-remove.d.ts +7 -0
- package/cli/dist/commands/self-remove.d.ts.map +1 -0
- package/cli/dist/commands/self-remove.js +179 -0
- package/cli/dist/commands/self-remove.js.map +1 -0
- package/cli/dist/commands/show.d.ts.map +1 -1
- package/cli/dist/commands/show.js +29 -99
- package/cli/dist/commands/show.js.map +1 -1
- package/cli/dist/commands/skill.d.ts +67 -0
- package/cli/dist/commands/skill.d.ts.map +1 -0
- package/cli/dist/commands/skill.js +513 -0
- package/cli/dist/commands/skill.js.map +1 -0
- package/cli/dist/commands/unlink.d.ts +6 -0
- package/cli/dist/commands/unlink.d.ts.map +1 -0
- package/cli/dist/commands/unlink.js +115 -0
- package/cli/dist/commands/unlink.js.map +1 -0
- package/cli/dist/commands/validate.d.ts +6 -0
- package/cli/dist/commands/validate.d.ts.map +1 -0
- package/cli/dist/commands/validate.js +159 -0
- package/cli/dist/commands/validate.js.map +1 -0
- package/cli/dist/utils/catalog-sync.d.ts +22 -0
- package/cli/dist/utils/catalog-sync.d.ts.map +1 -0
- package/cli/dist/utils/catalog-sync.js +157 -0
- package/cli/dist/utils/catalog-sync.js.map +1 -0
- package/cli/dist/utils/character-count.d.ts +56 -0
- package/cli/dist/utils/character-count.d.ts.map +1 -0
- package/cli/dist/utils/character-count.js +190 -0
- package/cli/dist/utils/character-count.js.map +1 -0
- package/cli/dist/utils/documentation-validator.d.ts +18 -0
- package/cli/dist/utils/documentation-validator.d.ts.map +1 -0
- package/cli/dist/utils/documentation-validator.js +233 -0
- package/cli/dist/utils/documentation-validator.js.map +1 -0
- package/cli/dist/utils/install-rules.d.ts +32 -0
- package/cli/dist/utils/install-rules.d.ts.map +1 -0
- package/cli/dist/utils/install-rules.js +375 -0
- package/cli/dist/utils/install-rules.js.map +1 -0
- package/cli/dist/utils/mcp-integration.d.ts +70 -0
- package/cli/dist/utils/mcp-integration.d.ts.map +1 -0
- package/cli/dist/utils/mcp-integration.js +292 -0
- package/cli/dist/utils/mcp-integration.js.map +1 -0
- package/cli/dist/utils/module-system.d.ts +153 -0
- package/cli/dist/utils/module-system.d.ts.map +1 -0
- package/cli/dist/utils/module-system.js +528 -0
- package/cli/dist/utils/module-system.js.map +1 -0
- package/cli/dist/utils/modules-catalog.d.ts +33 -0
- package/cli/dist/utils/modules-catalog.d.ts.map +1 -0
- package/cli/dist/utils/modules-catalog.js +163 -0
- package/cli/dist/utils/modules-catalog.js.map +1 -0
- package/cli/dist/utils/rule-install-hooks.d.ts +19 -0
- package/cli/dist/utils/rule-install-hooks.d.ts.map +1 -0
- package/cli/dist/utils/rule-install-hooks.js +224 -0
- package/cli/dist/utils/rule-install-hooks.js.map +1 -0
- package/cli/dist/utils/skill-system.d.ts +95 -0
- package/cli/dist/utils/skill-system.d.ts.map +1 -0
- package/cli/dist/utils/skill-system.js +313 -0
- package/cli/dist/utils/skill-system.js.map +1 -0
- package/modules.md +518 -106
- package/package.json +12 -3
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
# Python Testing with pytest
|
|
2
|
+
|
|
3
|
+
Use pytest as the primary testing framework for Python projects.
|
|
4
|
+
|
|
5
|
+
## Test Organization
|
|
6
|
+
|
|
7
|
+
### Directory Structure
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
project/
|
|
11
|
+
├── src/
|
|
12
|
+
│ └── mypackage/
|
|
13
|
+
│ ├── __init__.py
|
|
14
|
+
│ └── module.py
|
|
15
|
+
└── tests/
|
|
16
|
+
├── __init__.py
|
|
17
|
+
├── conftest.py
|
|
18
|
+
├── test_module.py
|
|
19
|
+
└── integration/
|
|
20
|
+
└── test_integration.py
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Test File Naming
|
|
24
|
+
|
|
25
|
+
- Test files: `test_*.py` or `*_test.py`
|
|
26
|
+
- Test functions: `test_*`
|
|
27
|
+
- Test classes: `Test*`
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
# Good
|
|
31
|
+
test_user_authentication.py
|
|
32
|
+
test_data_processor.py
|
|
33
|
+
|
|
34
|
+
# Bad
|
|
35
|
+
user_tests.py
|
|
36
|
+
authentication.py
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Test Structure
|
|
40
|
+
|
|
41
|
+
### Arrange-Act-Assert Pattern
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
def test_user_creation():
|
|
45
|
+
# Arrange
|
|
46
|
+
username = "testuser"
|
|
47
|
+
email = "test@example.com"
|
|
48
|
+
|
|
49
|
+
# Act
|
|
50
|
+
user = User(username=username, email=email)
|
|
51
|
+
|
|
52
|
+
# Assert
|
|
53
|
+
assert user.username == username
|
|
54
|
+
assert user.email == email
|
|
55
|
+
assert user.is_active is True
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Test Function Naming
|
|
59
|
+
|
|
60
|
+
Use descriptive names that explain what is being tested:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
# Good
|
|
64
|
+
def test_user_login_with_valid_credentials():
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
def test_user_login_with_invalid_password_raises_error():
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
def test_empty_cart_total_is_zero():
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
# Bad
|
|
74
|
+
def test_login():
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
def test_user():
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
def test_1():
|
|
81
|
+
pass
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## pytest Fixtures
|
|
85
|
+
|
|
86
|
+
### Basic Fixtures
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
import pytest
|
|
90
|
+
|
|
91
|
+
@pytest.fixture
|
|
92
|
+
def sample_user():
|
|
93
|
+
"""Provides a sample user for testing"""
|
|
94
|
+
return User(username="testuser", email="test@example.com")
|
|
95
|
+
|
|
96
|
+
def test_user_profile(sample_user):
|
|
97
|
+
assert sample_user.username == "testuser"
|
|
98
|
+
assert sample_user.email == "test@example.com"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Fixture Scopes
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
@pytest.fixture(scope="function") # Default: new instance per test
|
|
105
|
+
def user():
|
|
106
|
+
return User()
|
|
107
|
+
|
|
108
|
+
@pytest.fixture(scope="class") # Shared across test class
|
|
109
|
+
def database():
|
|
110
|
+
db = Database()
|
|
111
|
+
yield db
|
|
112
|
+
db.close()
|
|
113
|
+
|
|
114
|
+
@pytest.fixture(scope="module") # Shared across module
|
|
115
|
+
def api_client():
|
|
116
|
+
return APIClient()
|
|
117
|
+
|
|
118
|
+
@pytest.fixture(scope="session") # Shared across entire test session
|
|
119
|
+
def config():
|
|
120
|
+
return load_config()
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Fixture Cleanup with yield
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
@pytest.fixture
|
|
127
|
+
def temp_file():
|
|
128
|
+
"""Creates a temporary file and cleans up after test"""
|
|
129
|
+
file_path = "temp_test_file.txt"
|
|
130
|
+
with open(file_path, "w") as f:
|
|
131
|
+
f.write("test data")
|
|
132
|
+
|
|
133
|
+
yield file_path
|
|
134
|
+
|
|
135
|
+
# Cleanup
|
|
136
|
+
if os.path.exists(file_path):
|
|
137
|
+
os.remove(file_path)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Parametrized Tests
|
|
141
|
+
|
|
142
|
+
### Basic Parametrization
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
import pytest
|
|
146
|
+
|
|
147
|
+
@pytest.mark.parametrize("input,expected", [
|
|
148
|
+
(1, 2),
|
|
149
|
+
(2, 4),
|
|
150
|
+
(3, 6),
|
|
151
|
+
(4, 8),
|
|
152
|
+
])
|
|
153
|
+
def test_double(input, expected):
|
|
154
|
+
assert double(input) == expected
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Multiple Parameters
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
@pytest.mark.parametrize("username,email,is_valid", [
|
|
161
|
+
("user1", "user1@example.com", True),
|
|
162
|
+
("user2", "invalid-email", False),
|
|
163
|
+
("", "user3@example.com", False),
|
|
164
|
+
("user4", "", False),
|
|
165
|
+
])
|
|
166
|
+
def test_user_validation(username, email, is_valid):
|
|
167
|
+
user = User(username=username, email=email)
|
|
168
|
+
assert user.is_valid() == is_valid
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Parametrize with IDs
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
@pytest.mark.parametrize("value,expected", [
|
|
175
|
+
(0, "zero"),
|
|
176
|
+
(1, "one"),
|
|
177
|
+
(2, "two"),
|
|
178
|
+
], ids=["zero", "one", "two"])
|
|
179
|
+
def test_number_to_word(value, expected):
|
|
180
|
+
assert number_to_word(value) == expected
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Mocking with pytest-mock
|
|
184
|
+
|
|
185
|
+
### Basic Mocking
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
def test_api_call(mocker):
|
|
189
|
+
# Mock external API call
|
|
190
|
+
mock_response = mocker.Mock()
|
|
191
|
+
mock_response.json.return_value = {"status": "success"}
|
|
192
|
+
mock_response.status_code = 200
|
|
193
|
+
|
|
194
|
+
mocker.patch("requests.get", return_value=mock_response)
|
|
195
|
+
|
|
196
|
+
result = fetch_data("https://api.example.com/data")
|
|
197
|
+
assert result["status"] == "success"
|
|
198
|
+
|
|
199
|
+
### Mock Object Methods
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
def test_user_save(mocker):
|
|
203
|
+
# Mock database save method
|
|
204
|
+
mock_db = mocker.Mock()
|
|
205
|
+
user = User(username="testuser", db=mock_db)
|
|
206
|
+
|
|
207
|
+
user.save()
|
|
208
|
+
|
|
209
|
+
# Verify method was called
|
|
210
|
+
mock_db.save.assert_called_once()
|
|
211
|
+
mock_db.save.assert_called_with(user)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Patch Functions
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
def test_send_email(mocker):
|
|
218
|
+
# Patch the send_email function
|
|
219
|
+
mock_send = mocker.patch("myapp.email.send_email")
|
|
220
|
+
|
|
221
|
+
notify_user("user@example.com", "Welcome!")
|
|
222
|
+
|
|
223
|
+
mock_send.assert_called_once_with(
|
|
224
|
+
to="user@example.com",
|
|
225
|
+
subject="Welcome!",
|
|
226
|
+
body=mocker.ANY
|
|
227
|
+
)
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Exception Testing
|
|
231
|
+
|
|
232
|
+
### Testing Exceptions
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
import pytest
|
|
236
|
+
|
|
237
|
+
def test_division_by_zero():
|
|
238
|
+
with pytest.raises(ZeroDivisionError):
|
|
239
|
+
result = 10 / 0
|
|
240
|
+
|
|
241
|
+
def test_invalid_email_raises_validation_error():
|
|
242
|
+
with pytest.raises(ValidationError) as exc_info:
|
|
243
|
+
validate_email("invalid-email")
|
|
244
|
+
|
|
245
|
+
assert "Invalid email format" in str(exc_info.value)
|
|
246
|
+
|
|
247
|
+
def test_user_not_found_raises_custom_error():
|
|
248
|
+
with pytest.raises(UserNotFoundError, match=r"User .* not found"):
|
|
249
|
+
get_user(999)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Test Markers
|
|
253
|
+
|
|
254
|
+
### Built-in Markers
|
|
255
|
+
|
|
256
|
+
```python
|
|
257
|
+
import pytest
|
|
258
|
+
|
|
259
|
+
@pytest.mark.skip(reason="Not implemented yet")
|
|
260
|
+
def test_future_feature():
|
|
261
|
+
pass
|
|
262
|
+
|
|
263
|
+
@pytest.mark.skipif(sys.version_info < (3, 10), reason="Requires Python 3.10+")
|
|
264
|
+
def test_python_310_feature():
|
|
265
|
+
pass
|
|
266
|
+
|
|
267
|
+
@pytest.mark.xfail(reason="Known bug, fix in progress")
|
|
268
|
+
def test_known_issue():
|
|
269
|
+
pass
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Custom Markers
|
|
273
|
+
|
|
274
|
+
```python
|
|
275
|
+
# pytest.ini or pyproject.toml
|
|
276
|
+
# [tool.pytest.ini_options]
|
|
277
|
+
# markers =
|
|
278
|
+
# slow: marks tests as slow
|
|
279
|
+
# integration: marks tests as integration tests
|
|
280
|
+
|
|
281
|
+
@pytest.mark.slow
|
|
282
|
+
def test_large_dataset_processing():
|
|
283
|
+
pass
|
|
284
|
+
|
|
285
|
+
@pytest.mark.integration
|
|
286
|
+
def test_database_connection():
|
|
287
|
+
pass
|
|
288
|
+
|
|
289
|
+
# Run only slow tests: pytest -m slow
|
|
290
|
+
# Skip slow tests: pytest -m "not slow"
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## Test Coverage
|
|
294
|
+
|
|
295
|
+
### Running with Coverage
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
# Install pytest-cov
|
|
299
|
+
pip install pytest-cov
|
|
300
|
+
|
|
301
|
+
# Run tests with coverage
|
|
302
|
+
pytest --cov=mypackage tests/
|
|
303
|
+
|
|
304
|
+
# Generate HTML coverage report
|
|
305
|
+
pytest --cov=mypackage --cov-report=html tests/
|
|
306
|
+
|
|
307
|
+
# Fail if coverage below threshold
|
|
308
|
+
pytest --cov=mypackage --cov-fail-under=80 tests/
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Coverage Configuration
|
|
312
|
+
|
|
313
|
+
```ini
|
|
314
|
+
# .coveragerc or pyproject.toml
|
|
315
|
+
[tool.coverage.run]
|
|
316
|
+
source = ["src"]
|
|
317
|
+
omit = [
|
|
318
|
+
"*/tests/*",
|
|
319
|
+
"*/migrations/*",
|
|
320
|
+
"*/__pycache__/*",
|
|
321
|
+
]
|
|
322
|
+
|
|
323
|
+
[tool.coverage.report]
|
|
324
|
+
exclude_lines = [
|
|
325
|
+
"pragma: no cover",
|
|
326
|
+
"def __repr__",
|
|
327
|
+
"raise AssertionError",
|
|
328
|
+
"raise NotImplementedError",
|
|
329
|
+
"if __name__ == .__main__.:",
|
|
330
|
+
"if TYPE_CHECKING:",
|
|
331
|
+
]
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## Best Practices
|
|
335
|
+
|
|
336
|
+
### DO
|
|
337
|
+
|
|
338
|
+
✅ Write tests for all public APIs
|
|
339
|
+
✅ Use descriptive test names
|
|
340
|
+
✅ Follow Arrange-Act-Assert pattern
|
|
341
|
+
✅ Use fixtures for common setup
|
|
342
|
+
✅ Mock external dependencies
|
|
343
|
+
✅ Test edge cases and error conditions
|
|
344
|
+
✅ Keep tests independent and isolated
|
|
345
|
+
✅ Aim for high test coverage (80%+)
|
|
346
|
+
|
|
347
|
+
### DON'T
|
|
348
|
+
|
|
349
|
+
❌ Test implementation details
|
|
350
|
+
❌ Write tests that depend on execution order
|
|
351
|
+
❌ Use sleep() for timing issues (use proper mocking)
|
|
352
|
+
❌ Test third-party library code
|
|
353
|
+
❌ Write overly complex tests
|
|
354
|
+
❌ Ignore failing tests
|
|
355
|
+
❌ Skip writing tests for "simple" code
|
|
356
|
+
|
|
357
|
+
## Example Test Suite
|
|
358
|
+
|
|
359
|
+
```python
|
|
360
|
+
import pytest
|
|
361
|
+
from myapp.models import User
|
|
362
|
+
from myapp.exceptions import ValidationError
|
|
363
|
+
|
|
364
|
+
class TestUser:
|
|
365
|
+
"""Test suite for User model"""
|
|
366
|
+
|
|
367
|
+
@pytest.fixture
|
|
368
|
+
def valid_user_data(self):
|
|
369
|
+
return {
|
|
370
|
+
"username": "testuser",
|
|
371
|
+
"email": "test@example.com",
|
|
372
|
+
"age": 25
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
def test_user_creation_with_valid_data(self, valid_user_data):
|
|
376
|
+
user = User(**valid_user_data)
|
|
377
|
+
assert user.username == valid_user_data["username"]
|
|
378
|
+
assert user.email == valid_user_data["email"]
|
|
379
|
+
assert user.age == valid_user_data["age"]
|
|
380
|
+
|
|
381
|
+
@pytest.mark.parametrize("invalid_email", [
|
|
382
|
+
"invalid",
|
|
383
|
+
"@example.com",
|
|
384
|
+
"user@",
|
|
385
|
+
"",
|
|
386
|
+
])
|
|
387
|
+
def test_user_creation_with_invalid_email_raises_error(self, invalid_email):
|
|
388
|
+
with pytest.raises(ValidationError):
|
|
389
|
+
User(username="test", email=invalid_email, age=25)
|
|
390
|
+
|
|
391
|
+
def test_user_full_name_property(self):
|
|
392
|
+
user = User(
|
|
393
|
+
username="jdoe",
|
|
394
|
+
email="jdoe@example.com",
|
|
395
|
+
first_name="John",
|
|
396
|
+
last_name="Doe"
|
|
397
|
+
)
|
|
398
|
+
assert user.full_name == "John Doe"
|
|
399
|
+
|
|
400
|
+
def test_user_save_calls_database(self, mocker):
|
|
401
|
+
mock_db = mocker.Mock()
|
|
402
|
+
user = User(username="test", email="test@example.com", db=mock_db)
|
|
403
|
+
|
|
404
|
+
user.save()
|
|
405
|
+
|
|
406
|
+
mock_db.save.assert_called_once_with(user)
|
|
407
|
+
```
|
|
408
|
+
```
|
|
409
|
+
|