Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update tests: 1. automl.py #1417

Merged
merged 21 commits into from
Mar 23, 2022
Merged

Update tests: 1. automl.py #1417

merged 21 commits into from
Mar 23, 2022

Conversation

eddiebergman
Copy link
Contributor

@eddiebergman eddiebergman commented Mar 11, 2022

This PR is the first of a few to address several issues with regards to testing. Notably, it is hard to understand what some tests are actually testing for as well as tests that end up testing multiple things. This first PR updates our testing framework and applies it to the testing of automl.py.

  • Split automl.py tests into seperate files.
  • Use caching and cases to allow tests to be split up without having to retrain a model for each test.
  • Updates pyproject.toml which causes imports to be resorted on many tests.
  • Add typing and some minor clean-up to AutoML

To address these issues, please refer to the docstring in conftest.py

"""
Testing
=======
The following are some features, guidelines and functionality for testing which makes
updating, adding and refactoring tests easier, especially as features and functionality
changes.

**Marks**
* todo - ``pytest.mark.todo``` to mark a test which xfails as it's todo
* slow - ``pytest.mark.slow``` to mark a test which is skipped if `pytest --fast`

**Documenting Tests**
To ease in understanding of tests, what is being tested and what's expected of the test,
each test should be documented with what it's parameters/fixtures are as well as what
the test expects to happen, regardless of the tests implemntation.

    Parameters
    ----------
    param1: Type
        ...

    param2: Type
        ...

    Fixtures
    --------
    make_something: Callable[..., Something]
        Factory to make Something

    Expects
    -------
    * Something should raise a ValueError when called with X as X is not handled by the
      validator Y.

**Test same module across files**
When a module has many complicated avenues to be tested, create a folder and split the
tests according to each avenue. See `test/test_automl` for example as the `automl.py`
module is quite complicated to test and all tests in a single file become difficult to
follow and change.

**pytest_cases**
Using pytest_cases, we seperate a `case`, something that defines the state of the
object, from the actual `test`, which tests properties of these cases.

A complicated example can be seen at `test/test_automl/cases.py` where we have
autoML instances that are classifier/regressor, fitted or not, with cv or holdout,
or fitted with no ensemble. TODO: Easier example.

Docs: https://smarie.github.io/python-pytest-cases/

**Caching**
Uses pytest's cache functionality for long training models so they can be shared between
tests and between different test runs. This is primarly used with `cases` so that tests
requiring the same kind of expensive case and used cached values.

Use `pytest --cache-clear` to clear the cahce

See `test/test_automl/cases.py` for example of how the fixtures from
`test/fixtures/caching.py` can be used to cache objects between tests.

**Fixtures**
All fixtures in "test/fixtures" are known in every test file. We try to make use
of fixture `factories` which can be used to construct objects in complicated ways,
removing these complications from the tests themselves, importantly, keeping tests
short. A convention we use is to prefix them with `make`, for example,
`make_something`. This is useful for making data, e.g. `test/fixtures/data::make_data`

..code:: python

    # Example of fixture factory
    @fixture
    def make_something():
        def _make(...args):
            # ... complicated setup
            # ... more complications
            # ... make some sub objects which are complicated
            return something

        return _make

    @parametrize("arg1", ['a', 'b', 'c'])
    def test_something_does_x(arg1, make_something):
        something = make_something(arg1, ...)
        result = something.run()
        assert something == expected
"""

@codecov
Copy link

codecov bot commented Mar 11, 2022

Codecov Report

Merging #1417 (665b467) into development (44b7836) will decrease coverage by 0.25%.
The diff coverage is 93.52%.

@@               Coverage Diff               @@
##           development    #1417      +/-   ##
===============================================
- Coverage        84.59%   84.33%   -0.26%     
===============================================
  Files              146      147       +1     
  Lines            11295    11293       -2     
  Branches          1931     1924       -7     
===============================================
- Hits              9555     9524      -31     
- Misses            1226     1256      +30     
+ Partials           514      513       -1     

Impacted file tree graph

This commit (too much) focues on extending our pytest capabilities to
make things more modular. Notably, making a fixtures and mocks folders
for testing so there is a unified source of mocks and fixture locations.

Split the tests for automl.py into seperate sub files to allow for an
easier time discerning what is being tested where.

Introduces `pytest_cases` to allow for easier future
testing of properties.

Introduces cached automl models to allow for a quicker time testing
attributes while keeping tests seperate and distinct.

This also rearragnes `unittest` import unfortunatly which causes many
files to be touched.
@eddiebergman eddiebergman changed the title Update tests Update tests: 1. automl.py Mar 22, 2022
@eddiebergman eddiebergman merged commit 6ce1a75 into development Mar 23, 2022
github-actions bot pushed a commit that referenced this pull request Mar 23, 2022
@mfeurer mfeurer deleted the update_tests branch April 19, 2022 08:40
eddiebergman added a commit that referenced this pull request Aug 18, 2022
* Add: Dedicated fixtures location

* Add: Typing to conftest

* Fix: More typing

* Move: Dask fixtures to own location

* Move: backend to it's own fixture location

* Move: Automlstub thing to it's own fixture

* Fix: docstring warning in conftest

* Fix: Remove dead code

* Add: Functionality to skip marked `slow` tests

* Add: Fixture for getting datasets

* Update: Tests for automl.py w/ fixtures, cases, mocks

This commit (too much) focues on extending our pytest capabilities to
make things more modular. Notably, making a fixtures and mocks folders
for testing so there is a unified source of mocks and fixture locations.

Split the tests for automl.py into seperate sub files to allow for an
easier time discerning what is being tested where.

Introduces `pytest_cases` to allow for easier future
testing of properties.

Introduces cached automl models to allow for a quicker time testing
attributes while keeping tests seperate and distinct.

This also rearragnes `unittest` import unfortunatly which causes many
files to be touched.

* Doc: Add documentation about our testing to conftest.py

* Doc: Add a bit more on documenting of tests

* Fix: Add pytest-cases to test dependancies

* Fix: Broken tests

* Fix: Failing test

* Fix: Ordering of check in `_includes`

* Remove `_includes` and use sets instead

* Fix: Black

* Update: test workflow knows about `.pytest_cache`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant