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

Migrating unittest to pytest 6 #4354

Merged
merged 19 commits into from
Sep 13, 2024

Conversation

prady0t
Copy link
Contributor

@prady0t prady0t commented Aug 18, 2024

I've tried using fixture and parameterized in this PR. Do let me know places I've missed (inside this PR).

#4156

geometry.print_parameter_info()

def test_geometry(self):
def test_geometry(self, geometry):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We initialise the geometry variable below, do we need it in the arguments of the function?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, this test can be refactored since we are testing the same thing repeatedly. Please add this to the tracking issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now sure how to refactor. Could you help me more?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually, in such situations, it's better to make the test shorter and distribute it into multiple tests. For example, here, you could rewrite test_geometry into an array of smaller tests (haven't added the self keyword here for brevity):

def test_battery_geometry_current_collector_tabs():
    geometry = pybamm.battery_geometry(
        options={
            "particle size": "distribution",
            "dimensionality": 1,
        },
    )
    assert "tabs" in geometry["current collector"]

and

def test_battery_geometry_cylindrical_dimensionality():
    geo = pybamm.geometric_parameters
    geometry = pybamm.battery_geometry(
        form_factor="cylindrical", options={"dimensionality": 1}
    )
    assert geometry["current collector"]["r_macro"]["min"] == geo.r_inner
    assert geometry["current collector"]["r_macro"]["max"] == 1

However, readability is important. So, if refactoring introduces too many conditions or makes the code hard to read, it is best to not bother and keep the test as is.

Another aspect is to remove the loops by parametrizing. For example, the loop for cc_dimension in [0, 1, 2]: can be refactored into

@pytest.mark.parametrize("cc_dimension", [0, 1, 2])
def test_battery_geometry_basics(cc_dimension):

and similarly

@pytest.mark.parametrize("electrode, particle_type", [
    ("negative", "primary"),
    ("negative", "secondary"),
    ("positive", "primary"),
    ("positive", "secondary"),
])
def test_battery_geometry_particle_phases(electrode, particle_type):
    options = {"particle phases": "2"}
    geometry = pybamm.battery_geometry(options=options)
    geo = pybamm.GeometricParameters(options=options)
# followed by the rest of the test

and so on. I hope this can get you going!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy to write more examples if needed, it's easier than you would think :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These examples looks enough to me. Thanks :)
I guess we don't need case or if/else then as we using parametrize marker?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some cases, we might still need them.

@pytest.mark.parametrize("foo, bar", [0, 1, 2, 3, 4])
def test_something(foo, bar):
    # Some logic for initialising "foo" and "bar" here
    # and setting attributes, etc.
    # [...]

    # Conditional logic
    match foo.value:
        case 1:
            # do something
            assert foo in bar
        case 3.value:
            # do something else
            assert bar in foo

    # not (1) and not (3) – i.e., for (0) or (2) or (4)
    # Some other logic that applies to the rest of the cases
    assert foo.value + bar.value > 30

but it depends on the test. It might be better to handle such cases without parameterizing them

else:
self.assertEqual(len(mesh[domain].edges), len(mesh[domain].nodes) + 1)
assert len(mesh[domain].edges) == len(mesh[domain].nodes) + 1

def test_exceptions(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test can be refactored, too.

tests/unit/test_models/test_base_model.py Outdated Show resolved Hide resolved
tests/unit/test_models/test_base_model.py Outdated Show resolved Hide resolved
tests/unit/test_models/test_base_model.py Outdated Show resolved Hide resolved
tests/unit/test_expression_tree/test_variable.py Outdated Show resolved Hide resolved
tests/unit/test_expression_tree/test_variable.py Outdated Show resolved Hide resolved
@prady0t
Copy link
Contributor Author

prady0t commented Sep 9, 2024

Not sure why the error is. I was getting another regex error locally can you run CI jobs again?

@agriyakhetarpal
Copy link
Member

Since this PR seems to have taken a bit of time (for all the right reasons), let's nudge this towards a merge asap and work on the parameterization in further, dedicated PRs in your coming weeks – once the pytest migration gets finished.

Signed-off-by: Pradyot Ranjan <[email protected]>
@prady0t
Copy link
Contributor Author

prady0t commented Sep 10, 2024

I reverted the changes in test_OKane2022.py I still need to figure out the regex error. In the meantime, I'm also working on the last migration. I'll try to open PR by today or tomorrow morning.

Signed-off-by: Pradyot Ranjan <[email protected]>
@prady0t
Copy link
Contributor Author

prady0t commented Sep 13, 2024

I've removed pytest conversion from test_base_battery_model.py. This should work

Copy link
Member

@agriyakhetarpal agriyakhetarpal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks nice, thanks, @prady0t! Just one more change, and we can merge this if the tests pass.

test_spm_2024_09_13-PM03_52.json Outdated Show resolved Hide resolved
Copy link

codecov bot commented Sep 13, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 99.41%. Comparing base (7f263e4) to head (5c1e293).
Report is 182 commits behind head on develop.

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #4354   +/-   ##
========================================
  Coverage    99.41%   99.41%           
========================================
  Files          292      292           
  Lines        22223    22223           
========================================
  Hits         22093    22093           
  Misses         130      130           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@agriyakhetarpal agriyakhetarpal merged commit c2d8ac2 into pybamm-team:develop Sep 13, 2024
26 checks passed
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.

4 participants