【妙用協程】-ユニットテストのsetupとtearDown

1437 ワード

多くのテストでは、起動時に何かをし、終了時に何かを整理する必要があります.一般的な方法は、これらの動作をsetupとtearDownの2つの方法に書き、ユニットテストフレームワークは、開始と終了時にこの2つの方法を呼び出すことを担当します.
class SomeTest(unittest.case.TestCase):
    def setUp(self):
        super(SomeTest, self).setUp()
        setup_db()

    def tearDown(self):
        clean_db()
        super(SomeTest, self).tearDown()

この書き方にはいくつか煩わしいところがある.まずはLogic Localityが悪い質問:setup_db()とclean_db()は2つに分かれており、中間に長いコードが隔てられている可能性があります.視覚的に直観できないガイダンスsetup_db()元とclean_db()はペアです.次に再利用が難しい問題(上綱上線では複雑度が管理しにくい問題)ですが、共通のsetupやtearDownを繰り返すのを避けるために一般的にUsingDbTestのようなベースクラスが抽出されます.このようにすべてのサブクラスはsuper(xxx,self)を覚えなければならない.setUp()は、ベースクラスのsetUpを上書きします.次に、複数の次元が必要なものを多重化する必要がある場合、例えばUsingDbTestのベースクラスがあり、UsingNetworkTestのベースクラスがあり、サブクラスに2つのベースクラスを継承させるのではないでしょうか(mixinは少し複雑すぎますか?)generatorを使用すると、この問題をうまく解決できます.まずsetupとtearDownを作る方法を書きます.
@contextlib.contextmanager
def using_db():
    setup_db()
    yield
    clean_db()

これでsetup_がよくわかりますdbとclean_dbはペアです.次に、この小さなコンテキストをプライマリテストロジックにアタッチします.
def apply_context(test, contextmanager):
    contextmanager.__enter__()
    test.addCleanup(lambda: contextmanager.__exit__(None, None, None))

class SomeTest(unittest.case.TestCase):
    def setUp(self):
        apply_context(self, using_db())

ここではユニットテストのaddCleanupの特性を利用して,tearDownをsetupdにコールバックするときに設定した.この方式を用いて,共通のsetupとtearDownの論理を継承するのではなく,組合せの方式で多重化することができる.