태그 보관물: readability

readability

아무것도 반환하지 않는 순수한 메소드에 대한 테스트를 어떻게 작성해야합니까? 값이 유효한 경우 아무 것도 수행하지 않거나

가치 검증을 다루는 많은 클래스가 있습니다. 예를 들어, RangeValidator클래스는 값이 지정된 범위 내에 있는지 확인합니다.

모든 유효성 검사기 클래스에는 값 is_valid(value)을 반환 True하거나 False값에 따라 달라지며 ensure_valid(value)지정된 값을 확인하고 값이 유효한 경우 아무 것도 수행하지 않거나 값이 미리 정의 된 규칙과 일치하지 않으면 특정 예외가 발생합니다.

현재이 방법과 관련된 두 가지 단위 테스트가 있습니다.

  • 유효하지 않은 값을 전달하고 예외가 발생했는지 확인합니다.

    def test_outside_range(self):
        with self.assertRaises(demo.ValidationException):
            demo.RangeValidator(0, 100).ensure_valid(-5)
    
  • 유효한 값을 전달하는 것입니다.

    def test_in_range(self):
        demo.RangeValidator(0, 100).ensure_valid(25)
    

두 번째 테스트는 예외를 처리하면 실패하고 ensure_valid아무 것도 처리하지 않으면 성공합니다 assert. 내부에 s 가 없다는 사실이 이상하게 보입니다. 그러한 코드를 읽는 사람은 즉시 아무것도하지 않는 것처럼 보이는 테스트가 왜 있는지 스스로에게 묻습니다 .

값을 반환하지 않고 부작용이없는 방법을 테스트 할 때 이것이 현재 관행입니까? 아니면 다른 방법으로 테스트를 다시 작성해야합니까? 아니면 내가하고있는 일을 설명하는 의견을 적어보십시오.



답변

대부분의 테스트 프레임 워크에는 “Does n’t throw”에 대한 명시 적 주장이 있습니다 (예 : Jasmine has expect(() => {}).not.toThrow();및 nUnit 및 friends도 있습니다).


답변

이것은 사용되는 언어와 프레임 워크에 크게 의존합니다. 로 말하면 NUnit, Assert.Throws(...)방법 이 있습니다. 람다 메소드를 전달할 수 있습니다.

Assert.Throws(() => rangeValidator.EnsureValid(-5))

에서 실행됩니다 Assert.Throws. 람다에 대한 호출은 대부분 try { } catch { }블록에 의해 랩핑되며 예외가 발생하면 어설 션이 실패합니다.

프레임 워크에서 이러한 방법을 제공하지 않으면 호출을 직접 래핑하여 해결할 수 있습니다 (C #으로 작성 중).

// assert that the method does not fail
try
{
    rangeValidator.EnsureValid(50);
}
catch(Exception e)
{
    Assert.IsTrue(false, $"Exception: {e.Message}");
}

// assert that the method does fail
try
{
    rangeValidator.EnsureValid(50);
    Assert.IsTrue(false, $"Method is expected to throw an exception");
}
catch(Exception e)
{
}

이것은 의도를보다 명확하게하지만 코드를 어느 정도 혼란스럽게 만듭니다. (물론이 모든 것을 방법으로 감쌀 수 있습니다.) 결국 그것은 당신에게 달려 있습니다.

편집하다

Doc Brown이 의견에서 지적했듯이 문제는 메소드가 throw되는 것이 아니라 throw되지 않음을 나타내는 것이 었습니다. NUnit에는 그에 대한 주장도 있습니다

Assert.DoesNotThrow(() => rangeValidator.EnsureValid(-5))


답변

어설 션이 필요하지 않은 이유와 왜 잊지 않았는지 명확하게 설명을 추가하십시오.

다른 답변에서 볼 수 있듯이 다른 코드는 코드를 더 복잡하고 어수선하게 만듭니다. 이 의견을 통해 다른 프로그래머는 테스트의 의도를 알 수 있습니다.

그러나 이런 종류의 테스트는 예외가되어야합니다 (말장난 의도는 없음). 당신이 그런 것을 정기적으로 쓰는 것을 발견한다면, 아마도 테스트가 디자인이 최적이 아니라고 알려줄 것입니다.


답변

일부 메소드가 올바르게 호출 (또는 호출되지 않음) 될 수도 있습니다.

예를 들어 :

public void SendEmail(User user)
     ... construct email ...
     _emailSender.Send(email);

테스트에서 :

emailSenderMock.VerifyIgnoreArgs(service =>
    service.Send(It.IsAny<Email>()),
    Times.Once
);


답변