255 lines
11 KiB
Markdown
255 lines
11 KiB
Markdown
|
# Configuration
|
||
|
|
||
|
## Decorator Parameters
|
||
|
|
||
|
These are the parameters for the decorator {meth}`pytest_csv_params.decorator.csv_params`.
|
||
|
|
||
|
### Overview
|
||
|
|
||
|
| Parameter | Type | Description | Example |
|
||
|
|------------------|--------------------------|----------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------|
|
||
|
| `data_file` | `str` | The CSV file to use, relative or absolute path | `"/var/testdata/test1.csv"` |
|
||
|
| `base_dir` | `str` (optional) | Directory to look up relative CSV files (see `data_file`); overrides the command line argument | `join(dirname(__file__), "assets")` |
|
||
|
| `id_col` | `str` (optional) | Column name of the CSV that contains test case IDs | `"ID#"` |
|
||
|
| `dialect` | `csv.Dialect` (optional) | CSV Dialect definition (see [Python CSV Documentation](https://docs.python.org/3/library/csv.html#dialects-and-formatting-parameters)) | `csv.excel_tab` |
|
||
|
| `data_casts` | `dict` (optional) | Cast Methods for the CSV Data (see "Data Casting" below) | `{ "a": int, "b": float }` |
|
||
|
| `header_renames` | `dict` (optional) | Replace headers from the CSV file, so that they can be used as parameters for the test function (since 0.3.0) | `{ "Annual Amount of Bananas": "banana_count", "Cherry export price": "cherry_export_price" }` |
|
||
|
|
||
|
### Detailed Description
|
||
|
|
||
|
#### `data_file`
|
||
|
|
||
|
This points to the CSV file to load for this test. You can use relative or absolute paths. If you use a relative path
|
||
|
and a `base_dir`, the `base_dir` is prepended to the `data_file`.
|
||
|
|
||
|
````{admonition} Hint
|
||
|
It's a good idea to put your CSV data files in a `test-assets` folder on the same level than your `test_something.py`
|
||
|
file.
|
||
|
|
||
|
Example Layout:
|
||
|
|
||
|
```text
|
||
|
tests/
|
||
|
+- test-assets/
|
||
|
| +- case1.csv
|
||
|
| +- case2.csv
|
||
|
+- test_case1.py
|
||
|
+- test_case2.py
|
||
|
```
|
||
|
|
||
|
Now use this for `data_file` and `base_dir` (in one of the `test_caseX.py`):
|
||
|
|
||
|
```python
|
||
|
from os.path import dirname, join
|
||
|
from pytest_csv_params.decorator import csv_params
|
||
|
|
||
|
@csv_params(data_file="case1.csv", base_dir=join(dirname(__file__), "test-assets"))
|
||
|
def test_case1():
|
||
|
...
|
||
|
```
|
||
|
````
|
||
|
|
||
|
#### `base_dir`
|
||
|
|
||
|
This is an optional parameter. Set it to the directory where the CSV file from the `data_file` parameter should be
|
||
|
looked up. If not `None` (which is the default value), the value will be prepended to the `data_file` value, as long as
|
||
|
`data_file` is not an absolute path.
|
||
|
|
||
|
See `--csv-params-base-dir` command line argument below also.
|
||
|
|
||
|
```{warning}
|
||
|
Setting `base_dir` to something that is not `None` overrides anything that is set by the `--csv-params-base-dir`
|
||
|
command line argument.
|
||
|
```
|
||
|
|
||
|
#### `id_col`
|
||
|
|
||
|
Name the column that contains the test case IDs. If `None` (which is the default value), no test case IDs will be
|
||
|
generated. In this case, pytest will create its own IDs based on the parameters for the test. The column name does not
|
||
|
need to be valid variable/argument name.
|
||
|
|
||
|
Example:
|
||
|
|
||
|
```text
|
||
|
"Test Case ID#", "val_a", "val_b"
|
||
|
"test-12 / 4", "1234", "4321"
|
||
|
"test-13 / 7", "3210", "0123"
|
||
|
"test-14 / 9", "5432", "2345"
|
||
|
```
|
||
|
|
||
|
The test case ID is in the column "Test Case ID#". You'd configure it like this:
|
||
|
|
||
|
```python
|
||
|
from os.path import dirname, join
|
||
|
from pytest_csv_params.decorator import csv_params
|
||
|
|
||
|
@csv_params(data_file=join(dirname(__file__), "test-assets", "case1.csv"), id_col="Test Case ID#")
|
||
|
def test_case1(param_1: str, param_2: str) -> None:
|
||
|
...
|
||
|
```
|
||
|
|
||
|
#### `dialect`
|
||
|
|
||
|
Set the CSV dialect, it must be of the type {class}`csv.Dialect`. A dialect defines how a CSV file looks like.
|
||
|
|
||
|
The default dialect is {class}`pytest_csv_params.dialect.CsvParamsDefaultDialect`.
|
||
|
|
||
|
A dialect consists of the following settings:
|
||
|
|
||
|
| Setting | Default value in {class}`~pytest_csv_params.dialect.CsvParamsDefaultDialect` |
|
||
|
|---------------------------------------|------------------------------------------------------------------------------|
|
||
|
| {attr}`~csv.Dialect.delimiter` | `","` |
|
||
|
| {attr}`~csv.Dialect.doublequote` | `True` |
|
||
|
| {attr}`~csv.Dialect.escapechar` | `None` |
|
||
|
| {attr}`~csv.Dialect.lineterminator` | `"\r\n"` |
|
||
|
| {attr}`~csv.Dialect.quotechar` | `'"'` |
|
||
|
| {attr}`~csv.Dialect.quoting` | {data}`csv.QUOTE_ALL` |
|
||
|
| {attr}`~csv.Dialect.skipinitialspace` | `True` |
|
||
|
| {attr}`~csv.Dialect.strict` | `True` |
|
||
|
|
||
|
See [Usage Examples](examples) to learn how to create your own decorator that would always use your own specific CSV
|
||
|
file dialect.
|
||
|
|
||
|
```{note}
|
||
|
Regardless of the format parameters you are defining, all values from the CSV file are read as `str`. You may need to
|
||
|
convert them into other types. This is where `data_casts` are for.
|
||
|
```
|
||
|
|
||
|
#### `data_casts`
|
||
|
|
||
|
This dictionary allows you to setup methods to convert the string values from the CSV files into types or formats
|
||
|
required for test execution.
|
||
|
|
||
|
```{admonition} Rule of thumb
|
||
|
1. You can use any method that accepts a single `str` parameter. It can return anything you need.
|
||
|
2. If you need to test your test code, you should prefer conversion methods over conversion lambdas.
|
||
|
```
|
||
|
|
||
|
Example:
|
||
|
|
||
|
```text
|
||
|
"Test Case ID#", "val_a", "val_b", "val_c", "val_d", "val_e"
|
||
|
"test-12 / 4", "2.022", "152", "1 x 3", "abcd", "flox"
|
||
|
"test-13 / 7", "3.125", "300", "2 x 4", "defg", "trox"
|
||
|
"test-14 / 9", "4.145", "150", "3x6x9", "hijk", "bank"
|
||
|
```
|
||
|
|
||
|
- The values of column "Test Case ID#" do not need any conversion. The column will serve as `id_col`.
|
||
|
- The values of column "val_a" should be converted into `float`. Since `float` is also a method, it can be used
|
||
|
directly.
|
||
|
- The values of column "val_b" should be converted into `int`. Since `int` is also a method, it can be used directly.
|
||
|
- The values of column "val_c" must be converted a bit more complex. We'll use a `lambda` for that.
|
||
|
- The values of column "val_d" don't need to be converted. They are `str`.
|
||
|
- The values of column "val_e" will be converted with a helper method (`convert_val_e`).
|
||
|
|
||
|
Implementation of this example:
|
||
|
|
||
|
```python
|
||
|
from typing import List, Optional, Tuple
|
||
|
from pytest_csv_params.decorator import csv_params
|
||
|
|
||
|
def convert_val_e(value: str) -> Tuple[bool, Optional[str]]:
|
||
|
str_val = None
|
||
|
bool_val = value.endswith("ox")
|
||
|
if bool_val:
|
||
|
str_val = value[:2]
|
||
|
return bool_val, str_val
|
||
|
|
||
|
@csv_params(
|
||
|
data_file="test1.csv",
|
||
|
id_col="Test Case ID#",
|
||
|
data_casts={
|
||
|
"val_a": float,
|
||
|
"val_b": int,
|
||
|
"val_c": lambda x: list(map(lambda y: y.strip(), x.split("x"))),
|
||
|
"val_e": convert_val_e,
|
||
|
},
|
||
|
)
|
||
|
def test_something(val_a: float, val_b: int, val_c: List[int], val_d: str, val_e: Tuple[bool, Optional[str]]) -> None:
|
||
|
...
|
||
|
```
|
||
|
|
||
|
```{note}
|
||
|
In this example, the columns were named as valid argument/parameter names. So there's no need for `header_renames` here.
|
||
|
```
|
||
|
|
||
|
#### `header_renames`
|
||
|
|
||
|
This dictionary allows to rename the column headers into valid argument names for your test methods. The plugin will try
|
||
|
to rename invalid header names by replacing invalid chars with underscores, but this might not result in well-formed and
|
||
|
readable names.
|
||
|
|
||
|
Example:
|
||
|
|
||
|
```text
|
||
|
"Test Case ID#", "Flux Compensator Setting", "Power Level"
|
||
|
"101 / 885 / 31", "1-1-2-1-2-7-5-3-4-9/7", "100 %"
|
||
|
"109 / 995 / 21", "3-2-2-2-6-4-2-2-1-2/8", "15 %"
|
||
|
"658 / 555 / 54", "3-2-3-4-5-6-7-3-2-3/2", "25 %"
|
||
|
```
|
||
|
|
||
|
Configuration of the decorator:
|
||
|
|
||
|
```python
|
||
|
from pytest_csv_params.decorator import csv_params
|
||
|
|
||
|
@csv_params(
|
||
|
data_file="test.csv",
|
||
|
id_col="Test Case ID#",
|
||
|
header_renames={
|
||
|
"Flux Compensator Setting": "flux_setting",
|
||
|
"Power Level": "power_level",
|
||
|
},
|
||
|
)
|
||
|
def test_something_else(fux_setting: str, power_level: str) -> None:
|
||
|
...
|
||
|
```
|
||
|
|
||
|
```{warning}
|
||
|
`data_casts` dictionary keys must match the renamed column names!
|
||
|
```
|
||
|
|
||
|
## Command Line Arguments
|
||
|
|
||
|
These are the command line arguments for the pytest run.
|
||
|
|
||
|
### Overview
|
||
|
|
||
|
| Argument | Required | Description | Example |
|
||
|
|-------------------------|---------------|----------------------------------------------------------------------|----------------------------------------------|
|
||
|
| `--csv-params-base-dir` | no (optional) | Define a base dir for all relative-path CSV data files (since 0.1.0) | `pytest --csv-params-base-dir /var/testdata` |
|
||
|
|
||
|
### Detailed Description
|
||
|
|
||
|
#### `--csv-params-base-dir`
|
||
|
|
||
|
This is a convenience command line argument. It allows you to set a base directory for all your CSV parametrized test
|
||
|
cases. If you use relative `data_file`s, this can be automatically prepended. You can still override this setting per
|
||
|
test by using the `base_dir` configuration.
|
||
|
|
||
|
## How a CSV file is found
|
||
|
|
||
|
```text
|
||
|
+-----------------------------------+ /-----------------------------------\
|
||
|
| data_dir is absolute path? | --- yes --- | use this path |
|
||
|
+-----------------------------------+ \-----------------------------------/
|
||
|
|
|
||
|
no
|
||
|
|
|
||
|
+-----------------------------------+ /-----------------------------------\
|
||
|
| is a base_dir set on the test? | --- yes --- | prepend base_dir to data_file |
|
||
|
+-----------------------------------+ \-----------------------------------/
|
||
|
|
|
||
|
no
|
||
|
|
|
||
|
+-----------------------------------+ /-----------------------------------\
|
||
|
| is command line argument given? | --- yes --- | prepend arg value to data_file |
|
||
|
+-----------------------------------+ \-----------------------------------/
|
||
|
|
|
||
|
no
|
||
|
|
|
||
|
/-----------------------------------\
|
||
|
| use data_file as relative path |
|
||
|
\-----------------------------------/
|
||
|
```
|