2010-04-20 3 views
6

저는 약간의 cli 프로그램을 작업하면서 단위 테스트를 시작하려고 노력해 왔습니다.단위 테스트에 적합하도록 데이터베이스 실행/커밋을 어떻게 다시 작성해야합니까?

내 프로그램은 기본적으로 명령 줄 인수와 옵션을 구문 분석하고 어떤 함수를 호출할지 결정합니다. 각 함수는 데이터베이스에 대해 일부 연산을 수행합니다.

그래서, 예를 들어, 내가 만드는 기능을 가지고 있습니다

def create(self, opts, args): 
    #I've left out the error handling. 
    strtime = datetime.datetime.now().strftime("%D %H:%M") 
    vals = (strtime, opts.message, opts.keywords, False) 
    self.execute("insert into mytable values (?, ?, ?, ?)", vals) 
    self.commit() 

내 테스트 케이스의 호출이 함수는 다음 행을 입력했는지 확인하는 선택 SQL을 실행해야 하는가? 합리적인 것 같지만 테스트를 더 어렵게 만듭니다. 뭔가를 반환하고 반환 값을 확인하기 위해 함수를 다시 작성하겠습니까?

감사

나는 확실히 테스트의 용이성을 위해이 방법을 리팩토링 것
+0

단위 테스트는 두 단어라고 생각합니다. –

답변

8

Alex의 대답은 의존성 주입 방식을 다룹니다. 또 다른 방법은 당신의 방법을 고려하는 것입니다. 그것은 그대로 SQL 문을 생성하고 SQL 문을 실행하는 두 단계로 구성됩니다. 두 번째 단계는 테스트하지 않으려는 것입니다. SQL 엔진이나 데이터베이스를 작성하지 않았 으면 제대로 작동한다고 가정 할 수 있습니다. 1 단계가 작업입니다. SQL 문을 생성하는 것입니다. 이 값을 사용 :

def create_sql(self, opts, args): 
    #I've left out the error handling. 
    strtime = datetime.datetime.now().strftime("%D %H:%M") 
    vals = (strtime, opts.message, opts.keywords, False) 
    return "insert into mytable values (?, ?, ?, ?)", vals 

def create(self, opts, args): 
    self.execute(*self.create_sql(opts, args)) 
    self.commit() 

create_sql 기능은 1 단계, 그리고 지금은 당신이 그것에 대해 직접 테스트를 작성 할 수있는 방법으로 표현 : 당신은 단지 1 단계를 테스트 할 수 있도록 그래서 당신은 코드를 다시 구성 할 수 있습니다 값을 반환하므로 해당 기능을 다루는 단위 테스트를 작성할 수 있습니다. create 함수 자체가 더 간단 해졌고 철저하게 테스트 할 필요가 없습니다. 실제로 SQL을 올바르게 실행한다는 몇 가지 테스트를 할 수 있지만 create의 모든 엣지 사례를 처리 할 필요는 없습니다.

BTW : This video from Pycon (Tests and Testability)이 흥미로울 수 있습니다.

6

는 - 예를 들어, 의존성 주입은 도움이 될 수 있습니다 :

def create(self, opts, args, strtime=None, exec_and_commit=None): 
    #I've left out the error handling. 
    if strtime is None: 
     strtime = datetime.datetime.now().strftime("%D %H:%M") 
    vals = (strtime, opts.message, opts.keywords, False) 
    if exec_and_commit is None: 
     exec_and_commit = self.execute_and_commit 
    exec_and_commit("insert into mytable values (?, ?, ?, ?)", vals) 

을 물론 이것은 당신이 다음 execute과를 호출하는 execute_and_commit 방법을 가정 commit 방법.

이렇게하면 테스트 코드는 strtime에 대해 알려진 값을 주입 할 수 있으며 호출 할 수있는 코드를 exec_and_commit으로 삽입하여 예상 인수와 함께 호출되는지 확인합니다.

0

파이썬 구문에 익숙하지 않지만 단위 테스트를 처음 사용하는 경우 가장 쉬운 방법은 명령 줄 args에 전달하는 메서드를 추출하고 sql 명령을 다시 사용하는 것입니다. 이 방법을 사용하면 실제 논리가있는 코드 부분을 테스트 할 수 있습니다. 다른 유형의 arg를 전달하고 sql 명령과 비교하여 결과를 확인하십시오. 유닛 테스트의 맛을 알기 시작하면 db를 업데이트하는 함수를 올바르게 호출했는지 테스트하기 위해 조롱과 종속성 삽입에 대해 조금 배울 수 있습니다.

바라건대 당신은 내가 파이썬 구문을 나보다 자바 C#을 문법에 익숙해 있습니다 :)

public string GetSqlCommand(string[] commandLineArgs) 
{ 
    //do your parsing here 
    return sqlCommand; 
} 
[Test] 
public void emptyArgs_returnsEmptySqlCommand() 
{ 
    string expectedSqlCommand=""; 
    assert.AreEqual(expectedSqlCommand, GetSqlCommand(new string[]) 
} 
3

는 일반적으로, 당신은 리팩토링하기 전에 장소에서 단위 테스트를해야 할 주요 변경이 이루어지지되도록하고 싶다. 그렇지만 테스트 기능을 사용하려면 일부 리팩토링이 필요할 수 있습니다 ...불행한 패러독스, 이전에 나를 물었다.

즉, 동작을 변경하지 않고도 안전하게 수행 할 수있는 몇 가지 작은 리팩토링이 있습니다. 이름 바꾸기 및 추출은 두 가지입니다.

Michael Feathers의 저서 레거시 코드으로 작업하는 것이 좋습니다. 테스트 가능성을위한 코드 리팩토링에 중점을 둡니다. 예제는 Java이지만, 개념은 Python에도 똑같이 적용됩니다.

+0

및 C++ 코드가 책에 사용되었습니다. – Gutzofter

관련 문제