python / python/mypy

Fully-fledged support for mocked objects

Offen
#9,776 8 Kommentare 15 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

feature
Vorherrschende Sprache
Python
Sterne
20.6k
Forks
3.3k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

Feature

I'd like to propose that fully-fledged support for mocked objects be added so that type checks work with spec'd mocks.

import mock
import typing


class Foo:
    def bar(self, a: int) -> str:
        return str(a)


# I want to pass a spec'd mock here (mock.create_autospec(spec=Foo)).
def test_something(foo: Foo):
    # I'd like to find a way for this to be accepted by mypy.
    # error: "Callable[[int], str]" has no attribute "return_value"
    foo.bar.return_value = "42"


# This can be resolved arduously by writing a custom protocol for each mock.
class BarMockProtocol(typing.Protocol):
    return_value: str

    def __call__(self, a: int) -> str:
        pass

    # def assert_called():
    #     ...
    # And so on...


class FooMockProtocol(typing.Protocol):
    bar: BarMockProtocol


def test_something_else(foo: FooMockProtocol):
    # Error as expected.
    # error: Incompatible types in assignment (expression has type "int", variable has type "str")
    foo.bar.return_value = 42

    # No error as expected.
    foo.bar.return_value = "42"


# This is what I'd suggest
def test_something_else_yet(foo: mock.Mock[Foo]):
    # Error
    foo.bar.return_value = 42
    # No error
    foo.bar.return_value = "42"


# Usage sample
foo_mock = mock.create_autospec(spec=Foo)
test_something_else_yet(foo_mock)

Pitch

Currently, it's difficult to fully utilise mypy with mocks. I can see the following options.

  1. Use typing.Any to disable type checks.
  2. Use the type of the mocked class and live/deal with errors when using mock-specific attributes and methods (e.g. return_value, assert_*).
  3. Write a custom protocol for every mocked class as demonstrated above.

In other words, it's a choice between boilerplate and limitations. Please do let me know if I missed anything.

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Es werden keine Implementierungsdateien oder Tests genannt. Beginne damit, die Foo-, create_autospec- und Mock-Beispiele des Issues in mypy zu reproduzieren, und untersuche dann, wie gemockte Objekte und aufrufbare Attribute typisiert werden. Als abgeschlossen gilt die Aufgabe, wenn Mocks mit Spec Zuweisungen an return_value mit Typprüfung ohne benutzerdefinierte Protokolle unterstützen und gleichzeitig Fehler für inkompatible Werte erhalten bleiben.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
devtools, testing-qa
Issue-Typ
Feature
Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Aktivitätsstatus
Veraltet
Klarheit
Muss geklärt werden
Anfängerfreundlichkeit
25/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.