ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Programming Ruby (26) 단위테스트 - 2
    Ruby 2016. 11. 14. 22:14
    [출처] Programming Ruby 
    (본 게시물은 저작권의 문제 발생시 출판사의 요청에 의해 삭제될 수 있습니다.)



    테스트 구조화


    다음 코드를 통해 단위 테스트를 위한 테스트 프레임워크를 읽어 들일 수 있다.


    require 'test/unit'


    순수하게 MiniTest만을 사용하는 경우 아래와 같이 사용한다.


    require 'minitest/unit'



    단위 테스트는 테스트케이스(test case)라 불리는 고수준 그룹과 테스트 메서드 자체인 저수준 그룹으로 나뉜다. 테스트 케이스는 일반적으로 특정코드 또는 기능에 관련된 모든 테스트를 포함한다. 테스트 케이스 안에서도, 단언문을 몇 개의 테스트 메서드로 분류하고 구성해서 넣을 수 있다. 

    테스트 케이스를 표현하는 클래스는 Test::Unit::TestCase의 하위 클래스여야 한다. 단언문을 포함하는 메서드는 반드시 이름이 test로 시작해야 한다. 이는 매우 중요하다. 테스트 프레임워크는 실행할 테스트를 찾기 위해 리플렉션(reflection)을 사용하며, test로 시작하는 이름의 메서드만이 테스트될 자격을 갖는다. 


    특정 시나리오를 따르는 클래스를 테스트해보자


    require 'test/unit'

    require_relative 'playlist_builder'


    class TestPlaylistBuilder < Test::Unit::TestCase


        def test_empty_playlist

            db = DBI.connect('DBI:mysql:playlists')

            pb = PlaylistBuilder.new(db)

            assert_empty(pb.playlist)

            db.disconnect

        end


        def test_artist_playlist

            db = DBI.connect('DBI:mysql:playlists')

            pb = PlaylistBuilder.new(db)

            pb.include_artist("krauss")

            refute_empty(pb.playlist, "Playlist shouldn't be empty")

            pb.playlist.each do | entry |

                assert_match(/krauss/i, entry.artist)

            end

            db.disconnect

        end


        def test_title_playlist

            db = DBI.connect('DBI:mysql:playlists')

            pb = Playlistbuilder.new(db)

            pb.include_title("midnight")

            refute_empty(pb.playlist, "Playlist shouldn't be empty")

            pb.playlist.each do | entry | 

                assert_match(/midnight/i, entry.title)

            end

            db.disconnect

        end


        # ...

    end


    실행결과

    Run options:

    # Running tests:

    ...

    Finished tests in 0.003197s, 938.3797 tests/s 

    3 tests, 46 assertions, 0 failures, 0 errors, 0 skips


    각 테스트는 DB에 접속하고 새로운 재생목록 빌더를 생성하는 것으로 시작하여 디비에 접속을 해제하는 것으로 끝난다.  이 모든 공통 코드를 뽑아 setup과 teardown 메서드로 만들 수 있다. TestCase 클래스 내에서 setup이라는 메서드는 모든 테스트 메서드 실행되기 직전에 실행되고 teardown 메서드는 모든 테스트 메서드가 각각 실행된 다음에 실행된다. 


    require 'test/unit'

    require_relative 'playlist_builder'

    class TestPlaylistBuilder < Test::Unit::TestCase

        def setup
            @db = DBI.connect('DBI:mysql:playlists')
            @pb = PlaylistBuilder.new(@db)
        end

        def teardown    
            @db.disconnect
        end

        def test_empty_playlist
            asssert_empty(pb.playlist)
        end

        def test_artist_playlist
            @pb.include_artist("krauss")
            refute_empty(@pb.playlist, "Playlist shouldn't be empty")
            @pb.playlist.each do | entry |
                assert_match(/krauss/i, entry.artist)
            end
        end

        def test_title_playlist
            @pb.include_title("midnight")
            refute_empty(@pb.playlist, "Playlist shouldn't be empty")
            @pb.playlist.each do | entry | 
                assert_match(/midnight/i, entry.title)
            end
        end

        # ...

    end




    테스트 조직하고 실행하기


    지금까지 살펴본 테스트 케이스는 모두 실행 가능한 Test:Unit 프로그램이었다. Roman이라는 클래스에 테스트 케이스가. test_roman.rb 파일에 들어 있다면 다음과 같이 테스트를 실행할 수 있다.


    $ ruby test_roman.rb

    Runoptions:

    #Running tests:

    ..

    Finished tests in blabla~

    2 tests, 8 assertions, 0 failures, 0 erros, 0 skips



    Test:Unit은 메인 프로그램이 없다는 것을 알아챌 정도로 똑똑하며, 그런 경우 모든 테스트 케이스 클래스를 모아서 하나씩 순서대로 실행한다. 


    원한다면 특정 테스트 메서드만 실행할 수도 있다.


    $ ruby test_roman.rb - n test_range

    Run options: -n test_range

    #Running tests:

    .

    Finished tests in 0.00002231s

    1tests, 2 assertions, 0 failures, 0 errors, 0 skips



    아니면 정규 표현식에 매치되는 이름을 가진 테스트만 실행할 수도 있다.


    $ ruby test_roman.rb -n /range/

    Run options: -n /range/

    #Running tests:
    .
    Finished tests in 0.00002231s

    1tests, 2 assertions, 0 failures, 0 errors, 0 skips


    위의 방법은 테스트를 그룹화 하는데 유용한 방법이다. 의미 있는 이름을 테스트에 붙이는 습관을 들이면 /cart/를 매칭해서 관된 모든 메서드를 수행할 수 있다.




    테스트는 어디에 넣을까?


    테스트 코드는 프로젝트의 test/ 디렉터리에 모든 테스트 소스파일을 넣어두자. 


    project/

        lib/

            project.rb

            ~~

        test/

            test_project.rb

            ..




    테스트 스위트


    규모가 커진 테스트 케이스 집합을 분류해 묶어서 관리하면 좋다. 어떤 테스트 케이스 그룹은 특정 함수에 대한 테스트를 수행하고 다른 테스트 그룹은 다른 함수를 테스트한다. 이 경우 테스트 케이스를 함께 묶어서 테스트 스위트로 만들면, 그 테스트 케이스들을 한 그룹으로 한꺼번에 실행할 수 있다. 

     

    이를 간단히 구현하기 위해서는 test/unit을 require하고 루비 소스 파일을 작성한 다음 그룹화된 테스트 케이스가 있는 각 파일들을 require하기만 하면 된다. 이런 방법으로 테스트 자원 계층을 구성할 수 있다.


    - 개발 테스트를 이름으로 실행할 수 있다.

    - 파일을 실행함으로써 파일 내의 모든 테스트를 실행할 수 있다.

    - 몇 개의 파일을 테스트 스위트로 묶어서 그들을 한꺼번에 한 단위 처럼 실행할 수 있다.

    - 테스트 스위트 몇 개를 묶어 또 다른 테스트 스위트를 만들 수 있다. 


    테스트 케이스를 갖고 있는 파일에는 tc_xxx라는 이름을 붙이고 테스트 스위트를 가진 파일에는 ts_xxx와 같이 이름을 붙인다. 대부분 사람들은 테스트 케이스 파일 앞에 test_접두사를 붙인다.


    # file ts_dbaccess.rb

    require 'test/unit'

    require_relative 'test_connect'

    require_relative 'test_query'

    require_relative 'test_update'

    require_relative 'test_delete'


    ts_dbaccess 파일을 실행하면 네 개의 파일에 들어 있는 모든 테스크 케이스가 실행 될 것이다. 





    끄읕.



Designed by Tistory.