[GO] Python-Debug- und Testmodul

Debugging und Unit-Test

Aussage behaupten

Löst eine AssertionError-Ausnahme aus, wenn der Variablentest falsch ist.

test = 0
data = "assertion error"

try:
    assert test,data
except AssertionError:
    print data
finally:
    print "the end"

Wenn es sich nur um den Teil der Assert-Anweisung handelt, können Sie ihn wie folgt ersetzen.

if __debug__:
  if not test
    raise AssertionError, data

Ausnahmetrennung und Inhaltsanzeige

somedata = 1

#Korrigieren Sie die Ausnahmen, die Sie abfangen möchten.
fatal_exceptions = (KeyboardInterrupt, MemoryError)

try:
    assert somedata
except fatal_exceptions, inst:  #Sie können den Inhalt der Ausnahme mit dem Argument inst erhalten.
    print type(inst)    #Ausnahmetyp anzeigen
    print inst          #Zeigen Sie den Inhalt der Ausnahme an
    raise
#Fangen Sie alle anderen Ausnahmen ab
except Exception, inst:
    print type(inst)    #Ausnahmetyp anzeigen
    print inst          #Zeigen Sie den Inhalt der Ausnahme an
finally:
    print "the end"

UnitTest Leicht modifizierte und hinzugefügte Beispiele aus dem offiziellen Tutorial.

import random
import unittest

class TestSequenceFunctions(unittest.TestCase):

    #Der Initialisierungsprozess wird jedes Mal aufgerufen
    #Darüber hinaus gibt es eine Methode, die nach Ausführung des Tests usw. aufgerufen wird.
    def setUp(self):
        self.seq = range(10)

    #Beschreiben Sie den Methodennamen beginnend mit test.
    def test_shuffle(self):
        random.shuffle(self.seq)
        self.seq.sort()

        #Überprüfen Sie, ob die beiden Argumente gleich sind.
        #Das Überprüfen auf Ungleichheit ist assertNotEqual()Sie können es mit tun.
        self.assertEqual(self.seq, range(10))

        #Auf Ausnahmen prüfen.
        # assertRaises(exception, callable, *args, **kwds)
        #Übergeben Sie args und kwds an die Funktion des zweiten Arguments und überprüfen Sie, ob die durch das erste Argument angegebene Ausnahme auftritt.
        self.assertRaises(TypeError, random.shuffle, (1,2,3))

    def test_choice(self):
        element = random.choice(self.seq)

        #Überprüfen Sie, ob der Wert des Arguments True ist.
        # bool(element)Entspricht ist True
        self.assertTrue(element in self.seq)

    def test_sample(self):

        #Wenn nur das Ausnahmeargument übergeben wird, wird der Kontextmanager zurückgegeben.
        #Sie können den zu testenden Code inline schreiben.
        with self.assertRaises(ValueError):
            random.sample(self.seq, 20)
        for element in random.sample(self.seq, 5):
            self.assertTrue(element in self.seq)

if __name__ == '__main__':
    
    # main()Kann mit ausgeführt werden.
    unittest.main()

    #Lassen Sie Tests einzeln ausführen.
    _test_choice = TestSequenceFunctions('test_choice')
    _test_sample = TestSequenceFunctions('test_sample')

    #Es kann in der Testsuite registriert und vom Läufer gemeinsam ausgeführt werden.
    TestSuite = unittest.TestSuite()
    TestSuite.addTest(_test_choice)
    TestSuite.addTest(_test_sample)
    runner = unittest.TextTestRunner()
    runner.run(TestSuite)

    #Mit dem Loader können Sie gemeinsam Testfunktionen abrufen.
    suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions)
    unittest.TextTestRunner(verbosity=2).run(suite)

traceback Der Stapel ist der Speicherbereich, in dem das Programm gerade ausgeführt wird. Ein Stack-Trace zeichnet den Ausführungsstatus (Funktionsname, aufrufender Funktionsname, Zeile, Anweisung, Dateiname) des Programms im Speicherbereich auf. Dies ist ein Objekt in Skriptsprachen wie Python. Es ist vorgesehen.

Erstens können Stapelverfolgungsinformationen von sys.exc_info () abgerufen werden.

exc_type, exc_value, exc_traceback = sys.exc_info()

Mit diesen drei Variablen als Argumente zeigen traceback.print_tb () und traceback.print_exception () Informationen an.

Wenn Sie jedoch traceback.print_exc () unten verwenden, können Sie die Variablenerfassung in sys.exc_info () weglassen und den Typ und den Inhalt anzeigen, was praktisch ist. Grundsätzlich können Sie dies verwenden.

import sys
import traceback

def somework():
    try:
        print a #Verwenden Sie undefinierte Variablen
    except Exception:
        print "error"
        traceback.print_exc(file=sys.stdout)
    finally:
        print "the end"

if __name__ == '__main__':
    somework()

Ausgabeergebnis Der Modulname, die Zeile, der Funktionsname, die Ursachenanweisung und die Ursachenfehlermeldung werden ausgegeben.

error
Traceback (most recent call last):
  File "/Users/test.py", line 8, in somework
    print a
NameError: global name 'a' is not defined
the end

Dies ist die Ausgabe, wenn kein Traceback geschrieben wird. Es wird nichts ausgegeben, nur die Ausnahme übergeben.

error
the end

Als nächstes wird ein Verfahren zum Erfassen von Stapelverfolgungsinformationen als Liste einschließlich Taples gezeigt. Hier ist auch ein Beispiel für das Abrufen einer Variablen aus sys.exc_info (). (Weil es als Argument verwendet wird)

import sys
import traceback

def somework():
    try:
        print a #Verwenden Sie undefinierte Variablen
    except Exception:
        print "error"
        exc_type, exc_value, exc_traceback = sys.exc_info()
        print traceback.extract_tb(exc_traceback) #Holen Sie sich nur aktuelle Informationen
        print traceback.extract_stack() #Holen Sie sich ein Taple mit den Funktionsinformationen des Anrufers

        #Rufen Sie dies auf, wenn Sie es nur in einer Liste anstelle eines Taples erhalten möchten, und vereinfachen Sie die Anzeige.
        traceback.format_tb(exc_traceback)
        traceback.format_stack()

        print "the end"

if __name__ == '__main__':
    somework()

nosetest

Ich bezog mich auf "Python Professional Programming".

Installation der Nase

pip install nose

Zu testende Klasse Diese Klasse addiert oder subtrahiert einfach Zahlen zu Ihrem Bankkonto.

# coding: UTF-8

class NotEnoughFundsException(Exception):
    pass

class BankAccount(object):

    def __init__(self):
        self._balance = 0

    def deposit(self, amount):
        self.balance += amount

    def withdraw(self, amount):
        self.balance -= amount

    def get_balance(self):
        return self._balance

    def set_balance(self, value):
        if value < 0:
            raise NotEnoughFundsException

        self._balance = value

    #Bereiten Sie einen Wrapper vor, damit Sie Getter und Setter verwenden können.
    #ausbalancieren=Oder+Diese Funktionen werden beim Zugriff mit automatisch aufgerufen.
    balance = property(get_balance, set_balance)

Schreiben Sie Code, um mit der Nase zu testen. Hier wird das Vorbereiten eines festen Werts zum Testen wie 100 oder 0 als Datenvorrichtung bezeichnet.

# coding: UTF-8

import unittest

class BankAccountTest(unittest.TestCase):

    def _getTarget(self):
        from bankaccount import BankAccount
        return BankAccount

    #Erstellen Sie eine zu testende Instanz.
    def _makeOne(self, *args, **kwargs):
        return self._getTarget()(*args, **kwargs)

    def test_construct(self):
        target = self._makeOne()
        self.assertEqual(target._balance, 0)

    def test_deposit(self):
        target = self._makeOne()
        target.deposit(100)
        self.assertEqual(target._balance, 100)

    def test_withdraw(self):
        target = self._makeOne()
        target._balance = 100
        target.withdraw(20)
        self.assertEqual(target._balance, 80)

    def test_get_blance(self):
        target = self._makeOne()
        target._balance = 500
        self.assertEqual(target.get_balance(), 500)

    def test_set_balance_not_enough_funds(self):
        target = self._makeOne()
        from bankaccount import NotEnoughFundsException
        try:
            target.set_balance(-1)
            self.fail()
        except NotEnoughFundsException:
            pass

Legen Sie die beiden oben genannten in dasselbe Verzeichnis und führen Sie die Nase in diesem Verzeichnis aus.

nosetest

.....
----------------------------------------------------------------------
Ran 5 tests in 0.004s

OK

Holen Sie sich Berichterstattung

pip install coverage
# nosetests -v --with-coverage
test_construct (test_bankaccount.BankAccountTest) ... ok
test_deposit (test_bankaccount.BankAccountTest) ... ok
test_get_blance (test_bankaccount.BankAccountTest) ... ok
test_set_balance_not_enough_funds (test_bankaccount.BankAccountTest) ... ok
test_withdraw (test_bankaccount.BankAccountTest) ... ok

Name          Stmts   Miss  Cover   Missing
-------------------------------------------
bankaccount      16      0   100%
----------------------------------------------------------------------
Ran 5 tests in 0.006s

OK

Es wird eine leicht lesbare Abdeckung ausgegeben.

Ausgabe im XUNIT-Format mit der Option "--with-xunit".

# nosetests -v -w . --with-coverage --with-xunit
test_construct (test_bankaccount.BankAccountTest) ... ok
test_deposit (test_bankaccount.BankAccountTest) ... ok
test_get_blance (test_bankaccount.BankAccountTest) ... ok
test_set_balance_not_enough_funds (test_bankaccount.BankAccountTest) ... ok
test_withdraw (test_bankaccount.BankAccountTest) ... ok

----------------------------------------------------------------------
XML: nosetests.xml
Name          Stmts   Miss  Cover   Missing
-------------------------------------------
bankaccount      16      0   100%
----------------------------------------------------------------------
Ran 5 tests in 0.006s

OK

Ausgabe in XML, damit es von Jenkins gelesen werden kann.

coverage xml

mock

Normaler Gebrauch

Zu testende Klasse testモジュールのTest.py

# coding: UTF-8

class Widget(object):

    def __init__(self):
        self.value = 10

    def Additional(self, add):
        self.value += add
        return self.value

Testcode

from mock import Mock
from test import Test

def mock_value(value):
    return 20 + value

if __name__ == '__main__':

    #
    Test.Widget.Additional = Mock(return_value=100)

    w = Test.Widget()
    print w.Additional(1)

    #_
    Test.Widget.Additional = Mock(side_effect=mock_value)
    print w.Additional(1)
100
21

from mock import Mock
from test import Test

def mock_value(value):
    return 20 + value

if __name__ == '__main__':

    #
    Test.Widget = Mock()
    #
    Test.Widget.return_value.Additional.return_value = 10

    w = Test.Widget()
    print w.Additional(1)

    #Wenn Sie anstelle eines festen Werts eine Berechnung durchführen möchten, übergeben Sie eine Dummy-Funktion mit Nebeneffekt. Klasse durch Schein ersetzen Klasse selbst ersetzen. Der von der Funktion zurückgegebene Wert ist fest. Funktionen tauschen
    Test.Widget.return_value.Additional = mock_value
    print w.Additional(1)

patch Ersetzen Sie das Scheinobjekt, das die Funktion ausführt, durch das reale Objekt.

# coding: UTF-8

from mock import patch

#Geben Sie die Methode und den Rückgabewert an, die nur ersetzt werden sollen, während diese Funktion ausgeführt wird
@patch("Test.Widget.Additional", return_value=10)
def test_func(m): 

    import Test
    w = Test.Widget()
    print w.Additional(1)
    assert w.Additional(1) == 10

    #Übrigens ist m, das als Argument empfangen wird, eine zusätzliche Funktion, die durch einen Schein ersetzt wird.
    #Auch hier ist das Ergebnis 10.
    #Dieses Mal habe ich die Methode ersetzt, aber im Fall einer Klasse wird sie zu einer Klasse.
    print m()

if __name__ == '__main__':
    test_func()

Für das Kontextmanagerformat mit

# coding: UTF-8

from mock import patch

def test_func():

    #Geben Sie die Methode und den Rückgabewert an, die nur während dieser Ausführung durch den Bereich ersetzt werden sollen
    with patch("Test.Widget.Additional", return_value=10) as m:
        import Test
        w = Test.Widget()
        print w.Additional(1)
        assert w.Additional(1) == 10
        print m()

if __name__ == '__main__':
    test_func()

Klassentypspezifikation

mock = Mock(spec=SomeClass)
isinstance(mock, SomeClass) #Dies ist erfolgreich

Geben Sie Mock-spezifische Attribute an

# coding: UTF-8
from mock import Mock, patch

if __name__ == '__main__':
    #Eine Methode, die 3 mit der Namensmethode zurückgibt.
    #Eine Methode, die eine KeyError-Ausnahme mit dem Namen other auslöst
    attrs = {'method.return_value': 3, 'other.side_effect': KeyError}

    #Sie können Attribute gleichzeitig mit der Deklaration hinzufügen(some_attribute)。
    mock = Mock(some_attribute='eggs', **attrs)

    print mock.some_attribute
    print mock.method()
    print mock.other()

Andere

Eine andere Sache, die nützlich zu sein scheint

@patch('sys.stdout', new_callable=StringIO)

Es wird also zum Zeitpunkt der Erstellung als StringIO-Objekt erstellt.

Sie können eine Pseudoklasse zum Testen schreiben und sie mit "Test.Widget =" zuweisen, ohne mock zu verwenden. Wenn Sie die Validierungsfunktion von mock nicht verwenden, ist diese Methode möglicherweise schneller.

Django-Webtest-Modul

Sehr nützlich zum Testen von Django.

pip install webtest
pip install django-webtest

Die Django-Anwendung sieht folgendermaßen aus:

mysite
|-mysite
|   |-__init__.py
|   |-settings.py
|   |-urls.py
|   |-wsgi.py
|-test app
|   |-__init__.py
|   |-form.py
|   |-modes.py
|   |-views.py
|   |-tests.py Schreiben Sie diesen Test in diese Datei|
|-templates
|-manage.py

Schreiben Sie den Inhalt von tests.py wie folgt

from django_webtest import WebTest

class TestIndex(WebTest):

    def test_index(self):
        res = self.app.get("/") #Erhalten Sie die Antwort

        #Überprüfen Sie den Statuscode und den Inhalt.
        assert res.status == '200 OK'
        assert 'html' in res

Starten Sie den Entwicklungsserver mit manage.py runserver und führen Sie den Test mit dem folgenden Befehl aus.

# sudo python manage.py test testapp

Ausgabeergebnis

Creating test database for alias 'default'...
.
----------------------------------------------------------------------
Ran 1 test in 0.175s

OK
Destroying test database for alias 'default'...

Recommended Posts

Python-Debug- und Testmodul
Zusammenarbeit zwischen Python-Modul und API
Python 3-Socket-Modul und Socket-Kommunikationsfluss
Python-Modul importieren
Warteschlangen- und Python-Implementierungsmodul "deque"
Verteilung und Test
Python-Integritätstest
Python-Sammlungsmodul
Modulimport und Ausnahmebehandlung in Python
[Python] Klassentyp und Verwendung des datetime-Moduls
[Python] Komprimieren und dekomprimieren
Primzahlbeurteilung durch Python
Primzahlbeurteilung mit Python
Python- und Numpy-Tipps
[Python] Pip und Wheel
Python-Modul (Python-Lernnotiz ④)
Erstellen Sie ein Python-Modul
Import des Python-Originalmoduls
Python-Pakete und -Module
Python-Testpaket-Memo
Vue-Cli- und Python-Integration
Ruby, Python und Map
Primzahlbeurteilung mit Python
Python-Eingabe und Ausgabe
Python und Ruby teilen sich
Python-Tag-Kooperationstest
Python-Unit-Test-Vorlage
Python asyncio und ContextVar
Beispiel für das Abrufen des Modulnamens und des Klassennamens in Python
[Python of Hikari-] Kapitel 08-03 Modul (Import und Verwendung der Standardbibliothek)
Programmieren mit Python und Tkinter
Veriloggen und Cocotb werden nur zum Entwerfen und Testen von Verilog in Python verwendet.
Ver- und Entschlüsselung mit Python
Python-Modul-Importe alphabetisch sortieren
Python: Klassen- und Instanzvariablen
So funktioniert der Import von Python-Modulen
3-3, Python-Zeichenfolge und Zeichencode
Python 2-Serie und 3-Serie (Anaconda Edition)
Python auf Ruby und wütend Ruby auf Python
Python-Einzug und String-Format
Python Real Number Division (/) und Integer Division (//)
Installieren Sie Python und Flask (Windows 10)
[Python] ModuleNotFoundError: Kein Modul mit dem Namen 'urlparse'
Informationen zu Python-Objekten und -Klassen
Informationen zu Python-Variablen und -Objekten
Algorithmus in Python (Haupturteil)
Python-Modul num2words Verhaltensunterschied zwischen Englisch und Russisch
Apache mod_auth_tkt und Python AuthTkt
Å (Ongustorome) und NFC @ Python
Über das Python-Modul venv
Lernen Sie Python-Pakete und -Module kennen
# 2 [python3] Trennung und Kommentar aus
Flache Python-Kopie und tiefe Kopie
Python und Ruby Slice Memo
Python-Installation und grundlegende Grammatik
Flache Python-Kopie und tiefe Kopie
Debuggen Sie Python mit VS-Code
Über Python, len () und randint ()