You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Several changes to make the code base more consistent in naming, typing,
and use of connection vs session.
---------
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Copy file name to clipboardExpand all lines: docs/development/tests.md
+51-11Lines changed: 51 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -71,18 +71,58 @@ Some guidelines and things to keep in mind when writing tests:
71
71
- Try to keep tests small, so that they fail for one particular reason only.
72
72
- Mark tests that update the database in anyway with the `mut` marker (`@pytest.mark.mut`).
73
73
- If the test is excessively slow (>0.1 sec) and does not connect to PHP, use a `slow` marker. Tests that include PHP always require roundtrips through other services which makes them slow by default. PHP tests can be filtered out with the automatically generated "php_api" marker.
74
-
- Four common fixtures you might need when writing tests are:
75
-
-`py_api`: an async client for the Python based REST API
76
-
-`php_api`: an async client for the PHP based REST API
77
-
-`expdb_test`: an AsyncConnection to the "expdb" OpenML database.
78
-
-`user_test`: an AsyncConnection to the "openml" OpenML database.
79
-
- Above fixtures have considerable per-test overhead. Use them only when you need them.
80
74
- When writing assertions the expected value (a constant, or a php response) should be on the right (`assert response == expected`).
81
75
76
+
### Fixtures
77
+
There are a number of fixtures in `conftest.py`, here is a quick rundown of the most notable ones:
78
+
79
+
- `py_api` and `php_api`: an async client for the Python- and PHP-based REST APIs, respectively. The `py_api` client has its normal dependency injection for database connections patched to use the connection and session fixtures below.
80
+
- `expdb_connection` and `userdb_connection`: an AsyncConnection to the "expdb" OpenML database. This fixture is function-scoped and automatically starts a transaction which is rolled back as long as no `commit` is made.
81
+
- `expdb_session` and `userdb_session`: an AsyncSession that is bound to the respective connection. This means it also has automatic rollback. Any changes that need to be visible to the `py_api` fixture can be performed on this session (see below).
82
+
83
+
The pseudocode below shows how you might combine these for a test of the new REST API, either as standalone or when compared to the PHP API:
await expdb_connection.execute(text("INSERT INTO dataset ..."), parameters=...) # Insert dataset with id 42
97
+
await expdb_connection.commit() # We need to persist the data in the database, because the PHP REST API cannot see our transaction
98
+
99
+
response =await php_api.get("/datasets/42") # The PHP REST API can see the dataset, because it exists in the database
100
+
response =await py_api.get("/datasets/42") # The Python REST API can see the dataset also
101
+
102
+
# We need to clean up after ourselves, otherwise the test has side effects.
103
+
# This isn't a great pattern, prefer instead the use of context managers which will execute the delete statements even if unexpected exceptions occur.
104
+
await expdb_connection.execute(text("DELETE FROM dataset ..."), parameters=...)
105
+
await expdb_connection.commit()
106
+
107
+
```
108
+
109
+
???- "Why not always use the `*_connection`?"
110
+
111
+
As this implementation will make more and more use of ORM models, it is more convenient to have access to an `AsyncSession` object which can deal with those models.
112
+
Eventually, when verification against PHP REST API output is no longer necessary, we do not even need the `AsyncConnection` objects anymore at all.
113
+
114
+
115
+
Above fixtures have considerable per-test overhead. Use them only when you need them. More details in the next section.
116
+
82
117
### Writing Tests for an Endpoint
83
118
Because the `py_api` and database fixtures provide considerable per-test overhead,
84
119
follow these guidelines for writing a test suite for an endpoint.
85
120
121
+
!!! warning "Code snippets may not work"
122
+
123
+
The code below is provided as a guide, but isn't automatically tested (yet). This means it may be out of sync.
124
+
For examples that work, reference our test suite.
125
+
86
126
Include tests against `py_api` for input validation specific to that endpoint. Validation in reused components should be tested centrally (e.g., Pagination).
For all other tests, do not use `py_api` but call the implementing function directly. For example, do not call `client.get("/datasets/1")` but instead `get_dataset`:
You frequently need to write tests which include fetching from or writing to the database.
165
205
There is a test database that is prepopulated with data available for use as defined in our `compose.yaml` file.
166
206
167
-
The `expdb_test`and `user_test` connections automatically start a transaction during setup and perform a rollback during teardown.
207
+
The `expdb_connection`, `userdb_connection`, `expdb_session`, and `userdb_session` fixtures automatically start a transaction during setup and perform a rollback during teardown.
168
208
This means that as long as you do not `.commit()` any changes, the data will not persist.
169
209
This is a good thing. We do not want our tests to have side effects, as it might lead to inconsistent behavior.
0 commit comments