가치 검증을 다루는 많은 클래스가 있습니다. 예를 들어, 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
);