uokadaの見逃し三振は嫌いです

ここで述べられていることは私の個人的な意見に基づくものであり、私が所属する組織には一切の関係はありません。

nosetests を使ってをうるう年か判定する関数を実装してみた

とりあえず、nosetests, coverage のインストールから。
pip使ってインストールします。

% pip-2.7 install  nose coverage
Downloading/unpacking nose
  Downloading nose-1.1.2.tar.gz (729Kb): 729Kb downloaded
  Running setup.py egg_info for package nose
    
Downloading/unpacking coverage
  Downloading coverage-3.5.1.tar.gz (113Kb): 113Kb downloaded
  Running setup.py egg_info for package coverage
    
〜〜〜〜
    no previously-included directories found matching 'test'
    Installing coverage script to /Users/callistoiv/works/msgpackrpc/smigrate/bin
Successfully installed nose coverage
Cleaning up...

次に、テストコードの作成を行う。
本体のコードを先に書きたくなりますがここは我慢して先にテストコードを書きます。
今回はテストコードをtest_leap.py として保存。

#!/usr/bin/env python2.7
# -*- coding:utf-8 -*-

from nose.tools import *

import leap

class TestLeapYear(object):
    """TestLeapYear
        leap モジュールのテストクラス
    """
    def test_is_leap_01(self):
        """leap._is_leap の正常系テスト 01
        """
        result = leap.is_leap(2000)
        ok_(result)

    def test_is_leap_02(self):
        """leap._is_leap の正常系テスト 02
        """
        result = leap.is_leap(2004)
        ok_(result)

    def test_is_leap_03(self):
        """leap._is_leap の正常系テスト 03
        """
        result = leap.is_leap(1900)
        ok_(result == False)

    def test_is_leap_04(self):
        """leap._is_leap の正常系テスト 04
        """
        result = leap.is_leap(2001)
        ok_(result == False)

とりあえず、4つほどテスト条件を書いてみました。

3つめでやっと本体のコードの作成にとりかかります。
本体のコードは leap.pyで保存。

#!/usr/bin/env python2.7
# -*- coding:utf-8 -*-

def is_leap(year):
    """ judgement is leap
    """
    pass

まだ、実装は行わない。
ここまで準備できたらテストが失敗することを確認するために一度noseでテストを実行する

% nosetests  -v --with-cover --cover-package=leap test_leap.py
leap._is_leap の正常系テスト 01 ... FAIL
leap._is_leap の正常系テスト 02 ... FAIL
leap._is_leap の正常系テスト 03 ... FAIL
leap._is_leap の正常系テスト 04 ... FAIL

〜〜〜〜〜

Name    Stmts   Miss  Cover   Missing
-------------------------------------
leap        2      0   100%   
----------------------------------------------------------------------
Ran 4 tests in 0.004s

FAILED (failures=4)

オプションに関しては下のページ参照。
Cover: code coverage — nose 1.2.1 documentation
見事に全部のテストが失敗していますね。

というわけでここからis_leap()の実装を始めます。
今回は簡単に以下のようなコードにしてみました。

#!/usr/bin/env python2.7
# -*- coding:utf-8 -*-

def is_leap(year):
    """ judgement is leap
    """
    if year % 400 == 0:
        result = True
    elif year % 100 == 0:
        result = False
    elif year % 4 == 0:
        result = True
    else:
        result = False
    return result

これでテストが通るかnoseを実行します。

% nosetests  -v --with-cover --cover-package=leap test_leap.py
leap._is_leap の正常系テスト 01 ... ok
leap._is_leap の正常系テスト 02 ... ok
leap._is_leap の正常系テスト 03 ... ok
leap._is_leap の正常系テスト 04 ... ok

Name    Stmts   Miss  Cover   Missing
-------------------------------------
leap        9      0   100%   
----------------------------------------------------------------------
Ran 4 tests in 0.003s

OK

全部のテストがとおりましたね。
しかも、カバレッジ率100%です。つまり書いたコードをすべて実行しているってことですね。 *1

TDD簡単ですね!
これぐらい簡単なら毎日でもTDD出来ますね!*2
let's enjoy nosetests!

*1:正確には、もっと複雑なif文の条件式が含まれるコードでは条件式の一部が実行されていなくても100%になってしまいます。

*2:実際の現場ではクラス幾つかできてからあとでテスト作るってケースのほうがよくあります。テスト先に作る現場なんてかなり珍しいんじゃないかなって思います。