web-dev-qa-db-ja.com

例外を鼻でテストするにはどうすればよいですか?

例外を鼻でテストしています。次に例を示します。

def testDeleteUserUserNotFound(self):
    "Test exception is raised when trying to delete non-existent users"
    try:
        self.client.deleteUser('10000001-0000-0000-1000-100000000000')
        # make nose fail here
    except UserNotFoundException:
        assert True

例外が発生した場合はアサートが実行されますが、例外が発生しなかった場合は実行されません。

上記のコメント付きの行に何か例外を発生させない場合、鼻が失敗を報告するために何か私ができることはありますか?

32
BartD

noseは、(unittestのように)例外をテストするためのツールを提供します。この例を試してください(そして Nose Testing Tools で他のツールについて読んでください)

from nose.tools import *

l = []
d = dict()

@raises(Exception)
def test_Exception1():
    '''this test should pass'''
    l.pop()

@raises(KeyError)
def test_Exception2():
    '''this test should pass'''
    d[1]

@raises(KeyError)
def test_Exception3():
    '''this test should fail (IndexError raised but KeyError was expected)'''
    l.pop()

def test_Exception4():
    '''this test should fail with KeyError'''
    d[1]

これはあなたが探していた適切な方法であると私は思うでしょう。なぜならそれはあなたが期待する、または望む例外を特定できるからです。したがって、実際にエラーを引き起こして、適切な例外が発生することを確認します。そして、noseに結果を評価させます。 (単体テストにはできるだけ少ないロジックを入れてください!)

46
Malte

assert_raisesassert_raises_regexpおよびnose.toolsを使用することを強くお勧めします。これらは、unittest.TestCaseassertRaises および assertRaisesRegexp の動作を複製します。これらにより、実際にはunittest.TestCaseクラスを使用しないテストスイートでunittest.TestCaseによって提供されるのと同じ機能を使用できます。

@raisesは、あまりにも鈍い楽器であることがわかりました。ここに問題を示すコードがあります:

from nose.tools import *

something = ["aaa", "bbb"]

def foo(x, source=None):
    if source is None:
        source = something
    return source[x]

# This is fine
@raises(IndexError)
def test1():
    foo(3)

# This is fine. The expected error does not happen because we made 
# a mistake in the test or in the code. The failure indicates we made
# a mistake.
@raises(IndexError)
def test2():
    foo(1)

# This passes for the wrong reasons.
@raises(IndexError)
def test3():
    source = something[2]  # This is the line that raises the exception.
    foo(10, source)  # This is not tested.

# When we use assert_raises, we can isolate the line where we expect
# the failure. This causes an error due to the exception raised in 
# the first line of the function.
def test4():
    source = something[2]
    with assert_raises(IndexError):
        foo(10, source)

test3はパスしますが、fooが予期した例外を発生させたためではなく、fooが使用するデータを設定するコードが同じ例外で失敗したためです。 test4は、assert_raisesを使用してテストを記述し、テスト対象を実際にテストする方法を示しています。最初の行の問題により、Noseはエラーを報告します。次に、テストを書き直して、その行をテストして、テストの意味を最終的にテストできるようにします。

@raisesでは、例外に関連付けられたメッセージをテストできません。 ValueErrorをレイズする場合、1つの例を挙げると、通常は情報メッセージでレイズしたいと思います。次に例を示します。

def bar(arg):
    if arg:  # This is incorrect code.
        raise ValueError("arg should be higher than 3")

    if arg >= 10:
        raise ValueError("arg should be less than 10")

# We don't know which of the possible `raise` statements was reached.
@raises(ValueError)
def test5():
    bar(10)

# Yes, we're getting an exception but with the wrong value: bug found!
def test6():
    with assert_raises_regexp(ValueError, "arg should be less than 10"):
        bar(10)

test5を使用する@raisesはパスしますが、間違った理由でパスします。 test6は、より細かいテストを実行して、発生したValueErrorが目的のものではなかったことを明らかにします。

9
Louis
def testDeleteUserUserNotFound(self):
    "Test exception is raised when trying to delete non-existent users"
    try:
        self.client.deleteUser('10000001-0000-0000-1000-100000000000')
        assert False # <---
    except UserNotFoundException:
        assert True

try/exceptのセマンティクスは、実行フローが例外でtryブロックを離れることを意味するため、assert Falseは、例外が発生した場合は実行されません。また、tryブロックの実行が完了した後、実行によってexceptブロックに再び入ることはないため、問題が発生することはありません。

     ↓
(statements)
     ↓    exception
   (try) ↚──────────→ (except)
     ↓                   │
(statements) ←───────────┘
     ↓
9
badp

まだここにない理由はわかりませんが、もう1つの方法があります。

import unittest

class TestCase(unittest.TestCase):

    def testKeyError(self):
        d = dict()
        with self.assertRaises(KeyError):
            d[1]
7
66Ton99

使用する assert_raises

from nose.tools import assert_raises

our_method         = self.client.deleteUser
arg1               = '10000001-0000-0000-1000-100000000000'
expected_exception = UserNotFoundException

assert_raises(expected_exception, our_method, arg1)

テストでtry and catchを使用することは悪い習慣のようです(ほとんどの場合)。

それは基本的に単なるラッパーなので、鼻に特定のドキュメントはありません nittest.TestCase.assertRaises (ref。 鼻のassert_raisesの使い方?

3
l__flex__l

鼻が何であるかはわかりませんが、except句の後に「else」を使用してみましたか?つまり.

else:
    assert False
1
spicavigo