Skip to content

Commit

Permalink
Merge pull request #424 from pcattori/fake-json
Browse files Browse the repository at this point in the history
Utilities for fake resources
  • Loading branch information
pcattori committed Aug 1, 2020
2 parents 9735615 + a7cb558 commit 87eb698
Show file tree
Hide file tree
Showing 22 changed files with 401 additions and 238 deletions.
2 changes: 1 addition & 1 deletion docs/contributor-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ Submit feature requests as [Github issues](https://github.com/Datatamer/tamr-cli
* [Run dev tasks](contributor-guide/dev-tasks)
* [Configure your text editor](contributor-guide/text-editor)
* [Read the style guide](contributor-guide/style-guide)
* [How to write tests](contributor-guide/how-to-write-tests)
* [Submit a pull request](contributor-guide/pull-request)


## Maintainers

Maintainer responsabilities:
Expand Down
78 changes: 78 additions & 0 deletions docs/contributor-guide/how-to-write-tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# How to write tests

Our test suite uses `pytest`.

See the [pytest docs](https://docs.pytest.org/en/stable/) for:
- how to run specific tests
- how to capture `print` output for debugging tests
- etc...

Note that you will need to pass any `pytest` arguments after `--` so that `nox` passes the arguments correctly to `pytest`:

```sh
prn -s test-3.6 -- -s tests/tamr_client/test_project.py::test_from_resource_id_mastering
```

## Unit tests

Each unit test:
- must be in a Python file whose name starts with `test_`
- must be a function whose name starts with `test_`
- should test *one* specific feature.
- should use `tests.tamr_client.fake` utility to fake resources and Tamr server responses as necessary

For example, testing a simple feature that does not require communication with a Tamr server could look like:

```python
# test_my_feature.py
import tamr_client as tc
from tests.tamr_client import fake

def test_my_feature_works():
# prerequisites
p = fake.project()
d = fake.dataset()

# test my feature
result = tc.my_feature(p, d)
assert result.is_correct()
```

After using the `fake` utilities to set up your prerequisites,
the rest of the test code should be as representative of real user code as possible.

Test code that exercises the feature should not contain any test-specific logic.

### Faking responses

If the tested feature requires communication with a Tamr server,
you will need to fake Tamr server responses.

In general, any feature that takes a session argument will need faked responses.

You can fake responses via the `@fake.json` decorator:

```python
# test_my_feature.py
import tamr_client as tc
from tests.tamr_client import fake

@fake.json
def test_my_feature():
# prerequisites
s = fake.session()
p = fake.project()

# test my feature
result = tc.my_feature(s, p)
assert result.is_correct()
```

`@fake.json` will look for a corresponding fake JSON file within `tests/tamr_client/fake_json`,
specifically `tests/tamr_client/fake_json/<name of test file>/<name of test function>`.

In the example, that would be `tests/tamr_client/fake_json/test_my_feature/test_my_feature_works.json`.

The fake JSON file should be formatted as a list of request/response pairs in order of execution.

For a real examples, see existing fake JSON files within `tests/tamr_client/fake_json`.
2 changes: 1 addition & 1 deletion docs/contributor-guide/install.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Installation

### Pre-requisites
### Prerequisites

1. Install [build dependencies for pyenv](https://github.com/pyenv/pyenv/wiki#suggested-build-environment)
2. Install [pyenv](https://github.com/pyenv/pyenv#installation)
Expand Down
3 changes: 2 additions & 1 deletion stubs/responses.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from functools import partial
from typing import Any, Dict, Optional, TypeVar
from typing import Any, ContextManager, Dict, Optional, TypeVar

JsonDict = Dict[str, Any]

Expand All @@ -20,3 +20,4 @@ T = TypeVar("T")

def activate(T) -> T: ...
def add_callback(method: Optional[str], url: Optional[str], callback: partial[Any]): ...
def RequestsMock() -> ContextManager[Any]: ...
34 changes: 17 additions & 17 deletions tests/tamr_client/attribute/test_attribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import responses

import tamr_client as tc
from tests.tamr_client import utils
from tests.tamr_client import fake, utils


def test_from_json():
Expand Down Expand Up @@ -32,8 +32,8 @@ def test_json():

@responses.activate
def test_create():
s = utils.session()
dataset = utils.dataset()
s = fake.session()
dataset = fake.dataset()

attrs = tuple(
[
Expand Down Expand Up @@ -63,7 +63,7 @@ def test_create():

@responses.activate
def test_update():
s = utils.session()
s = fake.session()

url = tc.URL(path="datasets/1/attributes/RowNum")
attr_json = utils.load_json("attributes.json")[0]
Expand All @@ -80,7 +80,7 @@ def test_update():

@responses.activate
def test_delete():
s = utils.session()
s = fake.session()

url = tc.URL(path="datasets/1/attributes/RowNum")
attr_json = utils.load_json("attributes.json")[0]
Expand All @@ -92,8 +92,8 @@ def test_delete():

@responses.activate
def test_from_resource_id():
s = utils.session()
dataset = utils.dataset()
s = fake.session()
dataset = fake.dataset()

url = tc.URL(path=dataset.url.path + "/attributes/attr")
attr_json = utils.load_json("attribute.json")
Expand All @@ -105,8 +105,8 @@ def test_from_resource_id():

@responses.activate
def test_from_resource_id_attribute_not_found():
s = utils.session()
dataset = utils.dataset()
s = fake.session()
dataset = fake.dataset()

url = replace(dataset.url, path=dataset.url.path + "/attributes/attr")

Expand All @@ -116,17 +116,17 @@ def test_from_resource_id_attribute_not_found():


def test_create_reserved_attribute_name():
s = utils.session()
dataset = utils.dataset()
s = fake.session()
dataset = fake.dataset()

with pytest.raises(tc.attribute.ReservedName):
tc.attribute.create(s, dataset, name="clusterId", is_nullable=False)


@responses.activate
def test_from_dataset_all():
s = utils.session()
dataset = utils.dataset()
s = fake.session()
dataset = fake.dataset()

attrs_url = replace(dataset.url, path=dataset.url.path + "/attributes")
attrs_json = utils.load_json("attributes.json")
Expand All @@ -145,8 +145,8 @@ def test_from_dataset_all():

@responses.activate
def test_create_attribute_exists():
s = utils.session()
dataset = utils.dataset()
s = fake.session()
dataset = fake.dataset()

url = replace(dataset.url, path=dataset.url.path + "/attributes")
responses.add(responses.POST, str(url), status=409)
Expand All @@ -156,7 +156,7 @@ def test_create_attribute_exists():

@responses.activate
def test_update_attribute_not_found():
s = utils.session()
s = fake.session()

url = tc.URL(path="datasets/1/attributes/RowNum")
attr_json = utils.load_json("attributes.json")[0]
Expand All @@ -169,7 +169,7 @@ def test_update_attribute_not_found():

@responses.activate
def test_delete_attribute_not_found():
s = utils.session()
s = fake.session()

url = tc.URL(path="datasets/1/attributes/RowNum")
attr_json = utils.load_json("attributes.json")[0]
Expand Down
19 changes: 0 additions & 19 deletions tests/tamr_client/data/mastering_project.json

This file was deleted.

21 changes: 0 additions & 21 deletions tests/tamr_client/data/transformations.json

This file was deleted.

22 changes: 11 additions & 11 deletions tests/tamr_client/dataset/test_dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
import responses

import tamr_client as tc
from tests.tamr_client import utils
from tests.tamr_client import fake, utils


@responses.activate
def test_upsert():
s = utils.session()
dataset = utils.dataset()
s = fake.session()
dataset = fake.dataset()

url = tc.URL(path="datasets/1:updateRecords")
updates = [
Expand All @@ -37,8 +37,8 @@ def test_upsert():

@responses.activate
def test_upsert_primary_key_not_found():
s = utils.session()
dataset = utils.dataset()
s = fake.session()
dataset = fake.dataset()

df = pd.DataFrame(_records_json)

Expand All @@ -48,8 +48,8 @@ def test_upsert_primary_key_not_found():

@responses.activate
def test_upsert_infer_primary_key():
s = utils.session()
dataset = utils.dataset()
s = fake.session()
dataset = fake.dataset()

url = tc.URL(path="datasets/1:updateRecords")
updates = [
Expand All @@ -74,8 +74,8 @@ def test_upsert_infer_primary_key():

@responses.activate
def test_upsert_index_as_primary_key():
s = utils.session()
dataset = utils.dataset()
s = fake.session()
dataset = fake.dataset()

url = tc.URL(path="datasets/1:updateRecords")
updates = [
Expand Down Expand Up @@ -104,8 +104,8 @@ def test_upsert_index_as_primary_key():

@responses.activate
def test_upsert_index_column_name_collision():
s = utils.session()
dataset = utils.dataset()
s = fake.session()
dataset = fake.dataset()

df = pd.DataFrame(_records_json_2)
df.index.name = "primary_key"
Expand Down
10 changes: 5 additions & 5 deletions tests/tamr_client/dataset/test_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
import responses

import tamr_client as tc
from tests.tamr_client import utils
from tests.tamr_client import fake, utils


@responses.activate
def test_from_resource_id():
s = utils.session()
instance = utils.instance()
s = fake.session()
instance = fake.instance()

dataset_json = utils.load_json("dataset.json")
url = tc.URL(path="datasets/1")
Expand All @@ -22,8 +22,8 @@ def test_from_resource_id():

@responses.activate
def test_from_resource_id_dataset_not_found():
s = utils.session()
instance = utils.instance()
s = fake.session()
instance = fake.instance()

url = tc.URL(path="datasets/1")
responses.add(responses.GET, str(url), status=404)
Expand Down

0 comments on commit 87eb698

Please sign in to comment.