Help! My test isn't being type checked by mypy
Published on Jan 19, 2024 11:58 by KE Programmer
That was the issue I had this morning. I had written some piece of code with type annotations but obviously wrong type assignments in unit tests, but mypy was reporting that everything was OK.
I had code like this:
# lib.py from dataclasses import dataclass @dataclass class Question: text: str options: list['Option'] | None = None @dataclass class Option: text: str correct: bool = False
And a test like this:
# test_lib.py import unittest import lib class QuestionTestCase(unittest.TestCase): def test_create_question(self): q = lib.Question(text=1) q.options = 2 if __name__ == "__main__": unittest.main()
Type checking with mypy gave me no errors.
$ mypy lib.py test_lib.py
Success: no issues found in 2 source files
If you look at code, type checking the test code should produce errors
as I'm assigning an integer to Question.text instead of a a string,
and similarly, Question.options should be optional list of Option,
whereas I assigned an integer.
A bit of digging, and I found out that I had to add type annotations to the test methods as well like below. This would signal to mypy that I wanted to type check the method as well.
... class QuestionTestCase(unittest.TestCase): def test_create_question(self) -> None: # annotate here q = lib.Question(text=1) q.options = 2 ...
mypy should now show errors.
$ mypy lib.py test_lib.py test_lib.py:7: error: Argument "text" to "Question" has incompatible type "int"; expected "str" [arg-type] test_lib.py:8: error: Incompatible types in assignment (expression has type "int", variable has type "list[Option] | None") [assignment] Found 2 errors in 1 file (checked 2 source files)
Another option you can use, if you don't want to go annotating all
tests you already have, is to run mypy with the flag
--check-untyped-defs or add it in pyproject.toml.
$ mypy --check-untyped-defs lib.py test_lib.py test_lib.py:7: error: Argument "text" to "Question" has incompatible type "int"; expected "str" [arg-type] test_lib.py:8: error: Incompatible types in assignment (expression has type "int", variable has type "list[Option] | None") [assignment] Found 2 errors in 1 file (checked 2 source files)
This is explained on the page of Common Issues and solutions. The whole of it is worth reading.
I don't know why I haven't encountered this issue before over the
years, probably because the projects I've worked on didn't type check
unit tests or already had check-untyped-defs set.
It's probably useful every once in a while setting up a small projects by hand from scratch to identify such kinds of issues.
