Cool. That's what I wanted to see. By the way - not that there's anything wrong - but was the answer written by AI initially ? The first paragraph looks suspiciously like Chat GPT answer :D ?
Comment from my side: I personally prefer the original style. It's more concise and it is easier to read - you see as if the call was actually written down. Also this is quite a bit too many assertions in the second case and it takes a lot of mental effort to understand what actually is being asserted. There is a "school" of writing unit tests that every test should have ONE assertion only. Always. I think it is a bit extreme, and I do not follow it myself but I think it is also a kind of good direction to have -> the fewer assertions you have in your test, the better (I think). I think tests should be mostly optimized for easiness of reading and understanding what is being tested - and it's just not that easy in the second case. J. On Sat, Jul 5, 2025 at 1:39 PM Kyungjun Lee <kyungjunlee...@gmail.com> wrote: > Sure! Since you asked for how the test *should* be written, I took the > opportunity to clean it up using a more pytest-native style while also > fixing the mock order issue. > > Here’s the updated test: > > ```python > > @pytest.mark.parametrize( > argnames="conn_id, account_id", > argvalues=[(ACCOUNT_ID_CONN, None), (NO_ACCOUNT_ID_CONN, ACCOUNT_ID)], > ids=["default_account", "explicit_account"], > ) > @patch.object(DbtCloudHook, "run") > @patch.object(DbtCloudHook, "_paginate") > def test_get_account(self, mock_paginate, mock_http_run, conn_id, > account_id): > hook = DbtCloudHook(conn_id) > hook.get_account(account_id=account_id) > > assert hook.method == "GET" > > expected_account_id = account_id or DEFAULT_ACCOUNT_ID > > assert mock_http_run.call_count == 1 > assert mock_http_run.call_args.args == () > assert mock_http_run.call_args.kwargs == { > "endpoint": f"api/v2/accounts/{expected_account_id}/", > "data": None, > "extra_options": None, > } > > assert mock_paginate.call_count == 0 > > ``` > Why I chose this style: > > - > > *Mock verification using assert*: Instead of > mock.assert_called_once_with(...), I used call_count and call_args. This > approach aligns better with pytest’s idioms and produces cleaner, more > readable error messages when assertions fail. > - > > *Explicit verification*: Using call_args.args and call_args.kwargs makes > the test behavior very explicit, which helps with debugging and > understanding the exact calls made. > - > > *Decorator order matching argument order*: As @patch decorators apply > from the bottom up, the argument order has been corrected to match ( > mock_paginate first, then mock_http_run). > > Let me know if you'd like to follow a slightly different convention — happy > to adjust! > > I was lucky to have the chance to explain this while fixing a related bug. > You can refer to the changes in this PR: > https://github.com/apache/airflow/pull/52905 > > > > 2025년 7월 5일 (토) 오후 8:09, Jarek Potiuk <ja...@potiuk.com>님이 작성: > > > Just post how you think the test should be written :) > > > > On Sat, Jul 5, 2025 at 1:08 PM Jarek Potiuk <ja...@potiuk.com> wrote: > > > > > I already mentioned it in slack - but how would you propose to rewrite > > the > > > "mixed" case to be more consistent ? > > > > > > On Sat, Jul 5, 2025 at 12:47 PM Kyungjun Lee <kyungjunlee...@gmail.com > > > > > wrote: > > > > > >> Hi all, > > >> > > >> While reviewing and contributing to Airflow tests, I’ve noticed an > > >> inconsistency in how assertions are written. Some tests use > > >> `unittest`-style assertions like `mock.assert_called_once_with`, while > > >> others use plain `assert` statements in the `pytest` style. > > >> > > >> Here's an example of a test using the mixed style: > > >> > > >> ```python > > >> @pytest.mark.parametrize( > > >> argnames="conn_id, account_id", > > >> argvalues=[(ACCOUNT_ID_CONN, None), (NO_ACCOUNT_ID_CONN, > > ACCOUNT_ID)], > > >> ids=["default_account", "explicit_account"], > > >> ) > > >> @patch.object(DbtCloudHook, "run") > > >> @patch.object(DbtCloudHook, "_paginate") > > >> def test_get_account(self, mock_http_run, mock_paginate, conn_id, > > >> account_id): > > >> hook = DbtCloudHook(conn_id) > > >> hook.get_account(account_id=account_id) > > >> > > >> assert hook.method == "GET" > > >> > > >> _account_id = account_id or DEFAULT_ACCOUNT_ID > > >> hook.run.assert_called_once_with( > > >> endpoint=f"api/v2/accounts/{_account_id}/", data=None, > > >> extra_options=None > > >> ) > > >> hook._paginate.assert_not_called() > > >> ``` > > >> > > >> In IDEs and type-checkers (like PyCharm or MyPy), this sometimes > causes > > >> weak warnings > > >> > > >> ``` > > >> > > >> Cannot find reference 'assert_called_once_with' in 'function' > > >> > > >> ``` > > >> > > >> This could confuse newcomers or contributors unfamiliar with mocking > > >> behavior or type limitations in dynamic typing. > > >> > > >> To improve clarity and accessibility for contributors—especially those > > new > > >> to the project—I’d like to propose *moving toward consistent use of > > plain > > >> assert statements* for test validations wherever possible. > > >> > > >> *Proposed Benefits*: > > >> > > >> - > > >> > > >> Easier onboarding for first-time contributors > > >> - > > >> > > >> Better IDE support and fewer confusing warnings > > >> - > > >> > > >> More consistent and readable test style across the project > > >> > > >> I'd love to hear your thoughts on whether this direction makes sense > for > > >> the project. If agreed, I’d also be happy to help align existing tests > > >> gradually. > > >> > > >> Thanks! > > >> Kyungjun Lee > > >> > > > > > >