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

Adding Pytest Tests #65

Merged
merged 55 commits into from
Jul 29, 2022
Merged

Adding Pytest Tests #65

merged 55 commits into from
Jul 29, 2022

Conversation

callum-mcdata
Copy link
Contributor

Description

This PR adds pytest tests. It does NOT implement them as part of CI. That will take place in a following PR so that people don't have to review one massive PR and its instead 1 massive PR and one tiny PR. Wait....

Test Types Added:

  • base_metric_types: ensures that all the base metric types are working
  • compilation: ensures that metrics show up in manifest. More of a canary for something going wrong in dbt-core
  • expression_metric_types: ensures that expression metrics are working. We test for a simple calculation AND a ratio calculation to ensure div/0 not reintroduced
  • invalid configs: ensures that known issues or anti-patterns aren't breaking things
  • metric_options:
    • date_grains: checks that the default date grains of day, week, month all work correctly
    • dimensions: ensures that single and multi dimensions provided work correctly
    • end_date: ensures that the end date functionality works
    • multiple_metrics: ensures that multiple metrics work
    • start_date: ensures that the start date functionality works
    • secondary_calculations:
      • period_over_period: ensures that both period over period options work
      • period_to_date: ensures that all allowed options work for all metric types
      • rolling: ensures that all allowed options work for all metric types

@callum-mcdata callum-mcdata added the enhancement New feature or request label Jul 22, 2022
@cla-bot cla-bot bot added the cla:yes The CLA has been signed label Jul 22, 2022
@callum-mcdata callum-mcdata linked an issue Jul 22, 2022 that may be closed by this pull request
@callum-mcdata callum-mcdata self-assigned this Jul 25, 2022
Copy link
Contributor

@joellabes joellabes left a comment

Choose a reason for hiding this comment

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

I have reviewed five files! I think that is a representative set of the whole, but if there are things you think I should have looked at that got radio silence then let me know.

It's very possible that some of my complaints here come from being unfamiliar with pytest, but the things that are in here feel very fragile to me.

Comment on lines 13 to 17
dbt-core==1.2.0rc1
dbt-redshift==1.2.0rc1
dbt-snowflake==1.2.0rc1
dbt-bigquery==1.2.0rc1
Copy link
Contributor

Choose a reason for hiding this comment

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

How will these stay up to date over time?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We'll manually update these based on the version that we want to test. Right now its the RC candidate but we'll update it to v1.2 once it is no longer RC.

@@ -1,4 +1,4 @@
select
*
,round(order_total - (order_total/2)) as discount_total
,1 as discount_total
Copy link
Contributor

Choose a reason for hiding this comment

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

❓ this is weird, shouldn't it be a percentage or something? I just spent a bunch of time digging through the files trying to work out why the average discount was always 1 in your expectation seed.

The thing that worries me here is that if your source data isn't that varied then you don't actually get the benefit of testing the aggregations - what if something has gone horribly wrong and you're actually calculating max/min or something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Very good point - I was trying to keep it as simple as possible but if it doesn't represent the actual calculation then thats not helpful

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh actually this is still a holdover from integration testing! These will mainly just be used for local development as we move the CI testing to pytest to test functionality. So the old version with round is retained in the pytest models 👯

Comment on lines +2 to +5
2022-01-01,FALSE,1.00000000000000000000
2022-02-01,FALSE,1.00000000000000000000
2022-02-01,TRUE,1.00000000000000000000
Copy link
Contributor

Choose a reason for hiding this comment

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

This isn't testing much of anything (as mentioned above)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is fixed in the pytest framework - everything within the integration tests folder is a holdover from when we were doing it that way and I'm hesitant to delete anything until we've got it all migrated over.

Comment on lines 24 to 49
base_average_metric_yml = """
version: 2
models:
- name: base_average_metric
tests:
- dbt_utils.equality:
compare_model: ref('base_average_metric__expected')
metrics:
- name: base_average_metric
model: ref('fact_orders')
label: Total Discount ($)
timestamp: order_date
time_grains: [day, week, month]
type: average
sql: discount_total
dimensions:
- had_discount
- order_country
"""

# seeds/base_average_metric__expected.csv
base_average_metric__expected_csv = """
date_month,base_average_metric
2022-01-01,1.00000000000000000000
2022-02-01,1.3333333333333333
""".lstrip()
Copy link
Contributor

Choose a reason for hiding this comment

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

Okkkkkk so am I understanding this correctly:

These lines of hardcoded logic are the same as the ones that are up above as proper .sql/.yml/.csv files? So we're duplicating everything? How do they stay in sync? And why do we need the former if it's all just turning into string constants down here?

idk if this is pythonic or not, but I would strongly prefer something like

#https://stackoverflow.com/a/49564464/14007029
from pathlib import Path
base_average_metric_sql = Path('../models/base_average_metric.sql').read_text();
base_average_metric_yml = Path('../models/base_average_metric.yml').read_text();

Such that we don't have to redefine everything from scratch in two places 🤢

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not quite. There are static datasets/definitions contained in fixtures.py and those are then imported. The reason that I keep some components outside of it (like the definition of the metric) is so we can understand what metric is being tested while just looking at the single file.

If we're trying to be more pythonic then I should move that definition into the fixtures file.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK! I think I was caught up on thinking that the stuff in the integration tests project was this stuff's twin. Carry on!


# test tests
results = run_dbt(["test"]) # expect passing test
assert len(results) == 1
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the results object here? Is it an array of passing tests? I would sorta prefer that it returned all results, and a pass/fail, and then we could do whatever the python version of results.all(result => result.statuscode == 'PASS') is

Copy link
Contributor

Choose a reason for hiding this comment

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

Because otherwise anytime we add new tests, we have to go through and update the expected number of passes. (or, worse, we add a test which fails, we forget to update the expected count, and it sits there failing forever).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dbeatty10 would have more context around this area. I suspect it returns the results of each command and then we confirm that it matches what we expect. So if we added a new test we'd want to assert that only two tests were running

Choose a reason for hiding this comment

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

The example containing hard-coded numbers comes from here.

dbt_metrics doesn't need to do it that way if it doesn't want to. The important part is to verify that it works as expected for all the possible edge cases. And that it fails in the ways expected with bad input.

Comment on lines +106 to +107
result_statuses = sorted(r.status for r in results)
assert result_statuses == ["pass"]
Copy link
Contributor

Choose a reason for hiding this comment

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

OK maybe that's what this line is? but then I don't know what the above stuff is, and I still feel very uncomfortable about hardcoded numbers of things in test files

Copy link

@dbeatty10 dbeatty10 Jul 26, 2022

Choose a reason for hiding this comment

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

(Deleted my original comment here and moved it above)

This was referenced Jul 29, 2022
@callum-mcdata callum-mcdata merged commit 8a7693d into main Jul 29, 2022
@callum-mcdata callum-mcdata deleted the clean_adding_pytest branch July 29, 2022 20:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla:yes The CLA has been signed enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Adopting Pytest
3 participants