2008-10-29 8 views
124

아무 것도 반환하지 않는 메서드를 단위 테스트하는 가장 좋은 방법은 무엇입니까? 특히 C#.단위 테스트 무효 메서드?

내가 실제로 테스트하려고하는 것은 로그 파일을 가져 와서 특정 문자열에 대해 구문 분석하는 방법입니다. 그런 다음 문자열을 데이터베이스에 삽입합니다. 전에는 해본 적이 없지만 TDD에 처음 입문 한 것은 없습니다. 테스트 할 수 있는지 또는 테스트를 거치지 않은 것인지 궁금합니다.

+33

"TDD"는 사용하지 않는 것이 좋습니다. 당신은 TDD가 아닌 Unit Testing을하고 있습니다. TDD를하고 있다면 "방법을 테스트하는 방법"과 같은 질문은 결코 없을 것입니다. 테스트가 먼저 존재하고 질문은 "이 테스트를 통과하는 방법"이 될 것입니다. 그러나 TDD를하고 있다면 코드가 테스트 용으로 작성되고 (다른 방법은 아닙니다), 결국 자신의 질문에 대답하게됩니다. 귀하의 코드는 TDD 결과에 따라 다르게 서식이 지정되며,이 문제는 발생하지 않습니다. 그냥 명확히해라. – Suamere

답변

110

, 그것은 다음과 같은

  • 필수적 중 하나입니다 - 당신은 자신에게 뭔가를 할 객체를 요청하는 중입니다 .. 예를 들어 상태 변경 (어떤 기대없이 확인 .. 그것이 완료 될 것이라고 가정)
  • 정보 - 누군가에게 (행동이나 응답을 기대하지 않고) 일어난 일을 알리는 것만으로.

필수 방법 - 작업이 실제로 수행되었는지 확인할 수 있습니다.상태 변경이 실제로 발생했는지 확인하십시오. 예 : 따라서 ... 물체의 공중 인터페이스의 구성원으로 드물다 -이 메시지

정보 제공 방법 dAmount하여 초기 값보다 실제로 작 밸런스 포스트 경우

void DeductFromBalance(dAmount) 

을 확인하여 시험 할 수있다 일반적으로 단위 테스트를 거치지 않았습니다. 그러나 필요한 경우 알림에서 수행 할 처리가 수행되는지 확인할 수 있습니다. 예 :

void OnAccountDebit(dAmount) // emails account holder with info 

는 이메일이 실제 방법에 대해

포스트 자세한 내용을 전송되는 사람들이 더 나은 답변을 할 수있을 것입니다 경우 확인하여 테스트 할 수 있습니다.
업데이트 : 귀하의 방법은 2 가지 일을합니다. 나는 실제로 그것을 독립적으로 테스트 할 수있는 두 가지 방법으로 나누었습니다.

string[] ExamineLogFileForX(string sFileName); 
void InsertStringsIntoDatabase(string[]); 

문자열 []은 첫 번째 방법에 더미 파일과 예상되는 문자열을 제공하여 쉽게 확인할 수 있습니다. 두 번째는 약간 까다 롭습니다. 모의 (Google 또는 Mocking 프레임 워크의 stackoverflow 검색)를 사용하여 DB를 모방하거나 실제 DB를 쳐서 문자열이 올바른 위치에 삽입되었는지 확인할 수 있습니다. 좋은 책을 찾으려면 this thread을 확인하십시오 ... 위기에 처한 경우 Pragmatic Unit Testing을 추천합니다. 코드의
은이

InsertStringsIntoDatabase(ExamineLogFileForX("c:\OMG.log")); 
+0

자세한 내용은 위 – jdiaz

+1

안녕하세요, 좋은 답변입니다. 당신이 준 예제는 더 통합 테스트가 아닌가요? 그렇다면 문제는 남아 있습니다. 어떻게 Void Methods를 실제로 테스트 할 수 있습니까? 아마도 불가능할 것입니다. – andy

+1

@andy - '통합 테스트'의 정의에 따라 다릅니다. 명령형 메서드는 일반적으로 상태를 변경하므로 개체의 상태를 조사하는 단위 테스트를 통해 확인할 수 있습니다. 정보 제공 방법은 모의 청취자/협력자를 연결하는 단위 테스트를 통해 검증 할 수있어 테스트 주체가 올바른 통보를 발표 할 수 있도록합니다. 두 가지 모두 단위 테스트를 통해 합리적인 테스트를받을 수 있다고 생각합니다. – Gishu

5

효과 결과에 대한 개체 .... 쿼리에 약간의 영향을 미칩니다. 눈에 보이는 효과가 없다면 단위 테스트의 가치가 없습니다!

-1

또한 예외가 throw되는지 확인해야합니다.

+5

이것은 대답을위한 아주 예쁜 뼈입니다. 어쩌면 코멘트일까요? –

2

무엇을하고 있는지에 따라 다릅니다. 매개 변수가있는 경우 올바른 매개 변수 집합을 사용하여 호출 된 경우 나중에 요청할 수있는 모의 객체를 전달합니다.

+0

동의 - 테스트 방법을 테스트하는 모의 행위를 확인하는 것도 한 가지 방법입니다. –

22

항상 그렇듯 : 어떻게 해야하는지 테스트하십시오!

어딘가 전역 상태 (어, 코드 냄새!)가 바뀌어야합니까?

인터페이스를 호출해야합니까?

잘못된 매개 변수를 사용하여 호출 할 때 예외가 발생해야합니까?

올바른 매개 변수를 사용하여 호출 할 때 예외가 발생하지 않아야합니까?

해야할까요?

4

아마이 방법은 무언가를 수행하며 단순히 반환하지 않습니까?

이 경우는, 다음되는 가정 :

  1. 은 소유자 객체의의가 상태를 변경하는 경우, 당신은 상태가 제대로 변경하는지 테스트한다.
  2. 일부 개체를 매개 변수로 사용하여 해당 개체를 수정하는 경우 개체가 올바르게 수정되었는지 테스트해야합니다.
  3. 예외를 throw하는 경우가있는 경우 해당 예외가 올바르게 throw되는지 테스트하십시오.
  4. 동작이 자체 개체 또는 다른 개체의 상태에 따라 다를 경우 상태를 미리 설정하고 메서드가 위의 세 가지 테스트 방법 중 하나를 통해 올바른 방법으로 테스트하는지 테스트합니다.

이 방법이 무엇인지 알려 주시면 좀 더 구체적으로 설명해 드리겠습니다. 방법이 아무것도 반환하지 않는 경우

45

시험의 부작용과 같이 사용된다. 여기에는 다음이 포함됩니다.

  • 예외가 발생합니까? (만약 그것이 필요하다면, 그렇지 않다면 조심하지 않으면 어떤 모서리의 경우를 시도해보십시오. null 인수가 가장 명백한 것입니다.)
  • 그것의 매개 변수로 잘 작동합니까? (만약 그들이 변경 가능하다면, 변경해서는 안되며 변경할 필요가 없을 때 돌연변이합니까?)
  • 호출하고있는 객체/유형의 상태에 올바른 영향을 미칩니 까?

물론 을 테스트하는 데 한계가 있습니다. 일반적으로 가능한 모든 입력을 테스트 할 수는 없습니다. 실용적인 테스트 - 코드가 적절하게 설계되고 올바르게 구현되었다는 확신을 줄 수 있으며 호출자가 기대할 수있는 보완 문서로 사용할 수 있습니다.

3

Rhino Mocks을 사용하여 예상되는 호출, 동작 및 예외를 설정할 수 있습니다. 방법의 일부를 조롱하거나 스텁 (stub) 할 수 있다고 가정합니다. 방법, 또는 문맥에 대해서 여기에서 몇몇 특성을 모른 채로 알기가 어렵다.

+1

단위 테스트 방법에 대한 대답은 결코 당신을위한 제 3 자 도구를 제공해서는 안됩니다. 하지만 단위 테스트 방법을 아는 사람이라면 타사 도구를 사용하여 쉽게 단위 테스트를 수행 할 수 있습니다. – Suamere

5

보이드 리턴 유형/서브 루틴은 오래된 뉴스입니다. 저는 8 년 동안 (이 질문이 나오기 전에이 답을 할 때부터 너무 조금 게으르다가 아니라면) Void return 타입을 만들지 않았습니다.

public void SendEmailToCustomer() 

마이크로 소프트의 INT를 다음 방법을 확인 대신하는 방법 등을

.TryParse() 패러다임 :

public bool TrySendEmailToCustomer() 

아마 당신의 방법은 장기에서의 사용을 위해 반환 할 필요가있는 정보가 아니라, 방법의 상태를 반환하면 그 작업이에 큰 사용하는 것입니다 수행 한 후 방문객.

또한 bool만이 유일한 상태 유형이 아닙니다. 이전에 만들어진 서브 루틴이 실제로 3 가지 이상의 다른 상태 (양호, 보통, 불량 등)를 반환 할 수있는 횟수가 있습니다. 은 try-패러다임이 다소 무효 반환을 테스트하는 방법에 대한이 질문에 대한 대답하면서 이러한 경우에, 당신은 단지, 그러나

public StateEnum TrySendEmailToCustomer() 

사용하는 것, 다른 고려 사항도있다. 예를 들어, "TDD"주기 동안/후에 "리팩토링"하고 방법으로 두 가지 일을한다는 것을 알게되면 "단일 책임 원칙"을 위반하게됩니다. 그래서 그 일이 먼저 처리되어야합니다. 둘째, 당신은 종속성을 식별 할 수 있습니다 ... 당신은 "영구적 인"데이터를 만지고 있습니다.

질문에있는 방법으로 데이터 액세스 작업을 수행하는 경우 n 계층 또는 n 계층 아키텍처로 리팩토링해야합니다. 그러나 "문자열을 데이터베이스에 삽입 할 때"라고 말하면 실제로 비즈니스 로직 계층이나 다른 것을 호출한다는 것을 의미 할 수 있습니다. 예, 우리는 그것을 가정 할 것입니다.

개체가 인스턴스화되면 개체에 종속성이 있음을 알게되었습니다. 이것은 객체 나 메소드에서 의존성 주입을 할 것인지 결정할 필요가있을 때입니다. 당신이 당신의 사업/데이터 계층 객체의 인터페이스를 받아 들일 수 이제

public <Constructor/MethodName> (IBusinessDataEtc otherLayerOrTierObject, string[] stuffToInsert) 

, 당신은 단위 테스트 중에을 조롱하고 종속성을 가질 수 없습니다 : 그것은 당신의 생성자 또는 방법 -에 - 질문은 새로운 매개 변수를 필요로 의미 또는 우발적 인 통합 테스트에 대한 두려움.

실제 코드에서 REAL IBusinessDataEtc 개체를 전달합니다. 그러나 Unit Testing에서는 MOCK IBusinessDataEtc 객체를 전달합니다. 모의에서는 int XMethodWasCalledCount과 같은 비 인터페이스 속성이나 인터페이스 메소드가 호출 될 때 상태가 업데이트되는 것을 포함 할 수 있습니다.

당신의 단위 테스트는 자신의 논리를 수행하고 하나 또는 두 가지를 호출하거나 IBusinessDataEtc 개체에서 선택한 일련의 메서드를 호출합니다. Unit Test가 끝날 때 Assertions를 할 때, 지금 테스트 할 몇 가지 사항이 있습니다.

  1. Try-Paradigm 방법 인 "서브 루틴"의 상태.
  2. 귀하의 모의의 상태가 IBusinessDataEtc입니다.

단위 테스트와 관련된 빌드 수준의 종속성 주입 아이디어에 대한 자세한 내용은 빌더 디자인 패턴을 참조하십시오. 현재 인터페이스/클래스마다 하나의 인터페이스와 클래스를 추가하지만 매우 작으며 더 나은 단위 테스트를 위해 엄청난 기능 향상을 제공합니다.

2

이 시도 : 당신은 무효 메소드를 호출하는 데 사용하는 지금까지 어떤 예를

[TestMethod] 
public void TestSomething() 
{ 
    try 
    { 
     YourMethodCall(); 
     Assert.IsTrue(true); 
    } 
    catch { 
     Assert.IsTrue(false); 
    } 
} 
+1

이것은 필요하지 않지만 그렇게 할 수 있습니다. –

+0

Welcome to StackOverflow! 코드에 몇 가지 설명을 추가하십시오. 고맙습니다. – Aurasphere

+1

['ExpectedAttribute'] (https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.expectedexceptionattribute.aspx)는이 테스트를보다 명확하게하기 위해 고안되었습니다. –

-1

, 당신은 그냥 사용할 수 있습니다, 예를 들어 Verfiy

:

내 경우는 _Log가있다 인스턴스 및 LogMessage은 테스트 할 방법입니다.

try 
{ 
    this._log.Verify(x => x.LogMessage(Logger.WillisLogLevel.Info, Logger.WillisLogger.Usage, "Created the Student with name as"), "Failure"); 
} 
Catch 
{ 
    Assert.IsFalse(ex is Moq.MockException); 
} 

테스트가 실패하는 메서드의 실패로 인해 Verify이 예외를 throw합니까?

관련 문제