단위 테스트 무효 방법?


170

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

실제로 테스트하려고하는 것은 로그 파일을 가져 와서 특정 문자열에 대해 구문 분석하는 방법입니다. 그런 다음 문자열이 데이터베이스에 삽입됩니다. 이전에 수행되지 않았지만 TDD에 매우 새로운 것은 아무것도 테스트 할 수 있는지 또는 실제로 테스트되지 않은 것이 아닌지 궁금합니다.


55
그렇지 않은 경우 "TDD"라는 용어를 사용하지 마십시오. TDD가 아닌 단위 테스트를 수행하고 있습니다. TDD를 수행하는 경우 "방법을 테스트하는 방법"과 같은 질문이 없습니다. 테스트가 먼저 존재하고 "이 테스트를 통과시키는 방법"이 문제입니다. 그러나 TDD를 수행하면 테스트를 위해 코드가 작성되고 (다른 방법은 아님) 본질적으로 자신의 질문에 대답하게됩니다. TDD의 결과로 코드의 형식이 다르며이 문제는 발생하지 않았습니다. 명확하게.
Suamere

답변:


151

메소드가 아무것도 리턴하지 않으면 다음 중 하나입니다.

  • 명령 적 -객체가 스스로 무언가를하도록 요구하고 있습니다. 예 : 상태 변경 (확인을 기대하지 않고. 완료 될 것으로 가정)
  • 정보 -단지 행동이나 응답을 기대하지 않고 어떤 일이 발생했음을 누군가에게 알립니다.

명령 방식-작업이 실제로 수행되었는지 확인할 수 있습니다. 상태 변경이 실제로 발생했는지 확인하십시오. 예 :

void DeductFromBalance( dAmount ) 

이 메시지를 게시 한 잔액이 dAmount의 초기 값보다 작은 지 확인하여 테스트 할 수 있습니다

정보 방법-객체의 공용 인터페이스의 구성원으로서 드물기 때문에 일반적으로 단위 테스트를 거치지 않습니다. 그러나 필요한 경우 알림 처리가 수행되는지 확인할 수 있습니다. 예 :

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

이메일이 전송되고 있는지 확인하여 테스트 할 수 있습니다

실제 방법에 대한 자세한 내용을 게시하면 사람들이 더 잘 답변 할 수 있습니다.
업데이트 : 당신의 방법은 두 가지 일을하고 있습니다. 실제로 그것을 독립적으로 테스트 할 수있는 두 가지 방법으로 나눕니다.

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

첫 번째 방법에 더미 파일과 예상 문자열을 제공하면 String []을 쉽게 확인할 수 있습니다. 두 번째는 약간 까다 롭습니다. Mock (구글 프레임 워크의 Google 또는 검색 스택 오버 플로우)을 사용하여 DB를 모방하거나 실제 DB를 치고 문자열이 올바른 위치에 삽입되었는지 확인할 수 있습니다. 확인 이 스레드를 좋은 책을 ... 당신이 위기에 있다면 나는 실용 단위 테스트를 recomment 것입니다.
코드에서 다음과 같이 사용됩니다

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

1
이봐 기슈, 좋은 대답. 당신이 준 예제는 ... 더 많은 통합 테스트가 아닌가? 그렇다면 질문이 여전히 남아 있습니다. 어떻게 Void Methods를 실제로 테스트합니까? 어쩌면 불가능할까요?
andy

2
@andy- '통합 테스트'의 정의에 따라 다릅니다. 명령형 메소드는 일반적으로 상태를 변경하므로 객체 상태를 조사하는 단위 테스트로 확인할 수 있습니다. 테스트 대상이 올바른 알림을 발행하도록 모의 리스너 / 협업자를 연결하는 단위 테스트를 통해 정보 제공 방법을 확인할 수 있습니다. 두 가지 모두 단위 테스트를 통해 합리적인 테스트를 거칠 수 있다고 생각합니다.
Gishu

@andy 데이터베이스는 접근 자 인터페이스에 의해 조롱 / 분리 될 수 있으므로 조롱 객체에 전달 된 데이터에 의해 액션을 테스트 할 수 있습니다.
피터 가이거

62

부작용을 테스트하십시오. 여기에는 다음이 포함됩니다.

  • 예외가 발생합니까? (필요한 경우 확인하십시오. 그렇지 않은 경우주의하지 않아도 될 수있는 코너 사례를 시도해보십시오. 널 인수가 가장 명백합니다.)
  • 매개 변수로 훌륭하게 재생됩니까? (이들이 변이 가능하다면, 변하지 않아야 할 때 변이됩니까?)
  • 호출하는 객체 / 유형의 상태에 올바른 영향을 미칩니 까?

물론 테스트 할 수있는 에는 제한 이 있습니다. 예를 들어 일반적으로 가능한 모든 입력으로 테스트 할 수는 없습니다. 실용적으로 테스트-코드가 적절하게 설계되고 올바르게 구현되었음을 확신 할 수있을 정도로 충분하며 발신자가 기대할 수있는 보충 문서 역할을 할 수 있습니다.


31

항상 그렇듯이 : 방법이 무엇을해야하는지 테스트하십시오!

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

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

잘못된 매개 변수로 호출하면 예외가 발생합니까?

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

...해야합니까?


11

무효 반환 유형 / 서브 루틴은 오래된 뉴스입니다. 나는 8 년 동안 Void 반환 유형을 만들지 않았습니다 (내가 매우 게으르지 않은 한) (이 답변 시점 부터이 질문을하기 전에 조금만).

다음과 같은 방법 대신 :

public void SendEmailToCustomer()

Microsoft의 int.TryParse () 패러다임을 따르는 메소드를 작성하십시오.

public bool TrySendEmailToCustomer()

아마도 장기적으로 사용하기 위해 메소드가 리턴해야하는 정보가 없을 수도 있지만 메소드를 수행 한 후 메소드 상태를 리턴하는 것은 호출자에게 큰 도움이됩니다.

또한 bool이 유일한 상태 유형은 아닙니다. 이전에 만든 서브 루틴이 실제로 3 개 이상의 다른 상태 (Good, Normal, Bad 등)를 반환 할 수있는 경우가 많습니다. 이런 경우에는

public StateEnum TrySendEmailToCustomer()

그러나 Try-Paradigm은 보이드 리턴을 테스트하는 방법에 대해이 질문에 어느 정도 대답하지만 다른 고려 사항도 있습니다. 예를 들어, "TDD"주기 동안 / 후에, 당신은 "리팩토링 (refactoring)"을하게되며 방법으로 두 가지 일을하고 있다는 것을 알 수 있습니다. "단일 책임 원리" 따라서 먼저 처리해야합니다. 둘째로, 당신은 의존성을 이념화했을 수도 있습니다. 당신은 "영구적 인"데이터를 만지고 있습니다.

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

객체가 인스턴스화되면 이제 객체에 종속성이 있음을 이해합니다. 이것은 객체 또는 메소드에서 종속성 주입을 수행할지 여부를 결정해야 할 때입니다. 즉, 생성자 또는 요청 방법에 새로운 매개 변수가 필요합니다.

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

이제 비즈니스 / 데이터 계층 개체의 인터페이스를 수락 할 수 있으므로 단위 테스트 중에이를 모방 할 수 있으며 "사고"통합 테스트에 대한 종속성이나 두려움이 없습니다.

따라서 라이브 코드에서는 REAL IBusinessDataEtc객체 를 전달 합니다. 그러나 단위 테스트에서는 MOCK IBusinessDataEtc객체 를 전달 합니다. 모의 점에서, 당신은 비 인터페이스와 같은 속성이 포함될 수 있습니다 int XMethodWasCalledCount그 상태 (들) 인터페이스 메소드가 호출 될 때 업데이트됩니다 또는 무언가를.

따라서 단위 테스트는 질문에 대한 방법 (들)을 거치고, 가지고있는 논리를 수행하고, IBusinessDataEtc개체 에서 하나 또는 두 개 또는 선택된 메서드 집합을 호출 합니다. 단위 테스트가 끝날 때 어설 션을 수행하면 몇 가지 테스트 할 사항이 있습니다.

  1. Try-Paradigm 방법 인 "서브 루틴"의 상태.
  2. Mock IBusinessDataEtc객체 의 상태입니다 .

시공 레벨에 대한 의존성 주입 아이디어에 대한 자세한 내용은 유닛 테스팅과 관련이 있습니다. 현재 가지고있는 각각의 현재 인터페이스 / 클래스에 대해 인터페이스와 클래스를 하나 더 추가하지만, 매우 작으며 더 나은 단위 테스트를 위해 엄청난 기능 향상을 제공합니다.


이 위대한 답변의 첫 번째 덩어리는 모든 초보자 / 중급 프로그래머에게 놀라운 일반 조언 역할을합니다.
pimbrouwers

같은 것이 아니어야 public void sendEmailToCustomer() throws UndeliveredMailException합니까?
A.Emad

1
@ A.Emad 좋은 질문이지만 아닙니다. 예외 발생에 의존하여 코드 흐름을 제어하는 ​​것은 오랫동안 알려진 나쁜 사례입니다. 비록에 void특히 객체 지향 언어 방법, 그것은 유일한 옵션이었다. 마이크로 소프트의 가장 오래된 대안은 제가 이야기하는 Try-Paradigm과 Monads / Maybes와 같은 Functional-style 패러다임입니다. 따라서 CQS에서 Commands는 던지기에 의존하는 대신 여전히 가치있는 상태 정보를 반환 할 수 있습니다 GOTO. 던지기 (및 이동)는 느리고 디버깅하기가 어렵고 좋은 습관이 아닙니다.
메어

이것을 정리해 주셔서 감사합니다. C #에만 해당됩니까, 아니면 Java 및 C ++와 같은 언어에서도 예외를 발생시키는 것은 일반적으로 나쁜 습관입니까?
A.Emad

9

이 시도:

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

1
이것은 필수는 아니지만 그렇게 할 수 있습니다
Nathan Alard

StackOverflow에 오신 것을 환영합니다! 코드에 설명을 추가해보십시오. 감사합니다.
Aurasphere

2
ExpectedAttribute더 명확하게이 시험을 수 있도록 설계되었습니다.
Martin Liversage

8

이 방법으로 시도해 볼 수도 있습니다.

[TestMethod]
public void ReadFiles()
{
    try
    {
        Read();
        return; // indicates success
    }
    catch (Exception ex)
    {
        Assert.Fail(ex.Message);
    }
}

1
이것이 내가 생각하는 가장 간단한 방법입니다.
Navin Pandit

5

그것은 객체에 영향을 줄 것입니다 .... 결과에 대한 질의. 눈에 띄는 효과가 없다면 단위 테스트 가치가 없습니다!


4

아마도 메소드가 무언가를 수행하고 단순히 반환하지 않습니까?

이 경우를 가정하면 다음과 같습니다.

  1. 소유자 객체의 상태를 수정하면 상태가 올바르게 변경되었는지 테스트해야합니다.
  2. 일부 객체를 매개 변수로 가져 와서 해당 객체를 수정하면 객체를 올바르게 테스트해야합니다.
  3. 예외가 발생하는 경우가 있지만 예외가 올바르게 발생했는지 테스트하십시오.
  4. 동작이 자체 객체 또는 다른 객체의 상태에 따라 다른 경우 상태를 사전 설정하고 테스트하면 위의 세 가지 테스트 방법 중 하나를 통해 올바른 I를 갖습니다).

방법이 무엇인지 알려 주면 더 구체적 일 수 있습니다.


3

Rhino Mocks 를 사용 하여 어떤 호출, 동작 및 예외가 예상 될지 설정 하십시오 . 분석법의 일부를 조롱하거나 스터 빙 할 수 있다고 가정합니다. 방법이나 상황에 대한 구체적인 내용을 알지 못하면 알기가 어렵습니다.


1
단위 테스트 방법에 대한 해답은 절대 당신을 위해 그것을 수행하는 타사 도구를 얻는 것이어서는 안됩니다. 사람이 단위 테스트 방법을 알고있는 경우 타사 도구를 사용하여보다 쉽게 ​​테스트 할 수 있습니다.
Suamere

2

그것이하는 일에 달려 있습니다. 매개 변수가있는 경우 나중에 올바른 매개 변수 집합으로 호출되었는지 묻는 모의를 전달하십시오.


합의-방법을 테스트하는 모의 동작을 확인하는 것이 한 가지 방법입니다.
Jeff Schumacher

0

void 메소드를 호출하는 데 사용하는 인스턴스는 무엇이든 사용할 수 있습니다.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?

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.