webentwicklung-frage-antwort-db.com.de

Wie verwende ich die assertRaises () von Unit-Testing richtig mit NoneType-Objekten?

Ich habe einen einfachen Testfall gemacht:

def setUp(self):

  self.testListNone = None

def testListSlicing(self):

  self.assertRaises(TypeError, self.testListNone[:1])

und ich erwarte, dass der Test bestanden wird, aber ich bekomme eine Ausnahme:

Traceback (most recent call last):

    self.assertRaises(TypeError, self.testListNone[:1])

TypeError: 'NoneType' object is unsubscriptable

Ich dachte, dass assertRaises vergehen wird, da die TypeError-Ausnahme ausgelöst wird?

149
Andriusa

Wenn Sie Python2.7 oder höher verwenden, können Sie die Funktion assertRaises als Kontext-Manager verwenden und Folgendes tun:

with self.assertRaises(TypeError):
    self.testListNone[:1]

Wenn Sie Python2.6 verwenden, können Sie auch nittest2 verwenden. Dies ist ein Backport der unittest-Funktion von Python2.6, und Sie können es mit dem obigen Code zum Laufen bringen .

NB: Ich bin ein großer Fan der neuen Funktion (SkipTest, test discovery ...) von unittest, daher beabsichtige ich, unittest2 so oft wie möglich zu verwenden. Ich rate, dasselbe zu tun, da es in python2.6 <viel mehr gibt als das, was unittest mit sich bringt.

228
mouad

Das Problem ist, dass TypeError 'ausgelöst wird, bevor' assertRaises aufgerufen wird, da die Argumente für assertRaises ausgewertet werden müssen, bevor die Methode aufgerufen werden kann. Sie müssen einen lambda Ausdruck wie folgt übergeben:

self.assertRaises(TypeError, lambda: self.testListNone[:1])
120
Bas Bossink

Die übliche Methode, assertRaises zu verwenden, besteht darin, eine Funktion aufzurufen:

self.assertRaises(TypeError, test_function, args)

um zu testen, dass der Funktionsaufruf test_function (args) einen TypeError auslöst.

Das Problem mit self.testListNone[:1] Ist, dass Python) den Ausdruck unmittelbar vor dem Aufruf der assertRaises -Methode auswertet. Der ganze Grund, warum test_function Und args wird als separates Argument an self.assertRaises übergeben, damit assertRaisestest_function(args) aus einem try...except - Block aufrufen und assertRaises, um die Ausnahme abzufangen.

Da Sie self.testListNone = None Definiert haben und eine Funktion zum Aufrufen benötigen, können Sie operator.itemgetter wie folgt verwenden:

import operator
self.assertRaises(TypeError, operator.itemgetter, (self.testListNone,slice(None,1)))

schon seit

operator.itemgetter(self.testListNone,slice(None,1))

ist eine langatmige Art, self.testListNone[:1] zu sagen, die jedoch die Funktion (operator.itemgetter) von den Argumenten trennt.

78
unutbu

Das vollständige Snippet würde folgendermaßen aussehen. Es erweitert die Antwort von @ mouad auf die Behauptung der Fehlermeldung (oder allgemein die str Repräsentation der args), was nützlich sein kann.

from unittest import TestCase


class TestNoneTypeError(TestCase):

  def setUp(self): 
    self.testListNone = None

  def testListSlicing(self):
    with self.assertRaises(TypeError) as ctx:
        self.testListNone[:1]
    self.assertEqual("'NoneType' object is not subscriptable", str(ctx.exception))
5
saaj