[unit-testing] “Arrange-Assert-Act-Assert”여야합니까?

Arrange-Act-Assert 의 고전적인 테스트 패턴과 관련하여 저는 종종 Act 이전에 반대 주장을 추가하는 것을 발견합니다. 이렇게하면 전달 된 주장이 실제로 동작의 결과로 전달되고 있음을 알 수 있습니다.

Red-green-refactor의 빨간색과 유사하다고 생각합니다. 테스트 과정에서 빨간색 막대를 본 경우에만 초록색 막대가 차이를 만드는 코드를 작성했음을 의미합니다. 통과하는 테스트를 작성하면 모든 코드가 만족할 것입니다. 마찬가지로, Arrange-Assert-Act-Assert와 관련하여 첫 번째 주장이 실패하면 어떤 Act가 최종 Assert를 통과했을 것임을 알고 있습니다. 따라서 실제로 Act에 대한 어떤 것도 확인하지 않았습니다.

테스트가이 패턴을 따르나요? 그 이유는 무엇?

업데이트 설명 : 초기 주장은 본질적으로 최종 주장과 반대입니다. Arrange가 작동했다는 주장이 아닙니다. Act가 아직 작동하지 않았다는 주장입니다.



답변

이것은 가장 일반적인 일은 아니지만 자체 이름을 가질만큼 충분히 일반적입니다. 이 기술을 Guard Assertion 이라고 합니다. 훌륭한 책 xUnit Test Patterns 에서 490 페이지에 대한 자세한 설명을 찾을 수 있습니다.Gerard Meszaros (강력 권장) .

일반적으로이 패턴을 직접 사용하지 않습니다. 보장해야한다고 느끼는 전제 조건을 검증하는 특정 테스트를 작성하는 것이 더 정확하다는 것을 알기 때문입니다. 이러한 테스트는 전제 조건이 실패하면 항상 실패해야하며 이는 다른 모든 테스트에 포함 할 필요가 없음을 의미합니다. 하나의 테스트 케이스가 한 가지만 확인하므로 우려 사항을 더 잘 격리 할 수 ​​있습니다.

주어진 테스트 케이스에 대해 충족해야하는 전제 조건이 많을 수 있으므로 Guard Assertion이 두 개 이상 필요할 수 있습니다. 모든 테스트에서이를 반복하는 대신 각 전제 조건에 대해 하나의 테스트를 수행하면 테스트 코드를보다 쉽게 ​​관리 할 수 ​​있습니다. 그렇게하면 반복 횟수가 줄어들 기 때문입니다.


답변

Arrange- Assume -Act -Assert 로 지정할 수도 있습니다 .

NUnit에는 이에 대한 기술적 인 핸들이 있습니다. 예를 들면 다음과 같습니다.
http://nunit.org/index.php?p=theory&r=2.5.7


답변

여기에 예가 있습니다.

public void testEncompass() throws Exception {
    Range range = new Range(0, 5);
    assertFalse(range.includes(7));
    range.encompass(7);
    assertTrue(range.includes(7));
}

Range.includes()단순히 진실을 반환하기 위해 쓴 것일 수 있습니다 . 나는하지 않았지만 내가 가질 수 있다고 상상할 수 있습니다. 아니면 다른 여러 가지 방법으로 잘못 썼을 수도 있습니다. 나는 TDD를 사용하여 실제로 제대로 includes()작동하기를 희망하고 기대합니다 . 따라서 첫 번째 주장은 두 번째 주장이 실제로 의미가 있는지 확인하기위한 온 전성 검사입니다.

읽기 자체 assertTrue(range.includes(7));는 “수정 된 범위에 7이 포함됨”이라고 말합니다. 첫 번째 주장의 맥락에서 읽어보십시오. “envelope ()호출 하면 7이 포함 되도록 주장합니다 . 그리고 include는 우리가 테스트하는 단위이기 때문에 (작은) 값이라고 생각합니다.

나는 내 대답을 받아들이고있다. 다른 많은 사람들이 내 질문을 설정 테스트에 관한 것으로 오해했습니다. 약간 다른 것 같아요.


답변

Arrange-Assert-Act-Assert테스트는 항상 두 개의 테스트로 리팩토링 할 수있다 :

1. Arrange-Assert

2. Arrange-Act-Assert

첫 번째 테스트는 Arrange 단계에서 설정된 것에 대해서만 주장하고 두 번째 테스트는 Act 단계에서 발생한 것에 대해서만 주장합니다.

이것은 실패한 것이 Arrange 또는 Act 단계인지에 대해 더 정확한 피드백을 제공하는 이점이 있습니다. 반면 원본에서는 Arrange-Assert-Act-Assert이러한 단계가 결합되어 있으므로 더 깊이 파고 들어서 주장이 실패한 이유와 실패한 이유를 확인하기 위해 정확히 조사해야합니다. 실패한 것은 Arrange 또는 Act였습니다.

또한 테스트를 더 작은 독립 단위로 분리하므로 단위 테스트의 의도를 더 잘 충족시킵니다.

마지막으로, 다른 테스트에서 유사한 Arrange 섹션을 볼 때마다이를 공유 도우미 메서드로 가져와야합니다. 그래야 테스트가 더 건조 해지고 향후 유지 관리 가 쉬워 집니다.


답변

나는 지금 이것을하고있다. 다른 종류의 AAAA

Arrange - setup
Act - what is being tested
Assemble - what is optionally needed to perform the assert
Assert - the actual assertions

업데이트 테스트의 예 :

Arrange:
    New object as NewObject
    Set properties of NewObject
    Save the NewObject
    Read the object as ReadObject

Act:
    Change the ReadObject
    Save the ReadObject

Assemble:
    Read the object as ReadUpdated

Assert:
    Compare ReadUpdated with ReadObject properties

그 이유는 ACT가 ReadUpdated의 읽기를 포함하지 않는 이유는 그것이 행위의 일부가 아니기 때문입니다. 행위는 단지 변화하고 저장하는 것입니다. 실제로 어설 션을 위해 ARRANGE ReadUpdated를 사용하고 어설 션을 위해 ASSEMBLE을 호출합니다. 이것은 ARRANGE 섹션의 혼동을 방지하기위한 것입니다.

ASSERT는 어설 션 만 포함해야합니다. 어설 션을 설정하는 ACT와 ASSERT 사이에 ASSEMBLE이 남습니다.

마지막으로 Arrange에서 실패한 경우 이러한 사소한 버그 를 방지 / 찾을 수있는 다른 테스트가 있어야하므로 테스트가 올바르지 않습니다 . 내가 제시 한 시나리오의 경우 READ 및 CREATE를 테스트하는 다른 테스트가 이미 있어야합니다. “Guard Assertion”을 만들면 DRY를 깨고 유지 관리를 만들 수 있습니다.


답변

테스트중인 작업을 수행하기 전에 상태를 확인하기 위해 “건전성 검사”어설 션을 던지는 것은 오래된 기술입니다. 나는 보통 테스트 스캐 폴딩으로 작성하여 테스트가 내가 기대하는 바를 수행한다는 것을 스스로 증명하고 나중에 테스트 스캐 폴딩으로 복잡한 테스트를 피하기 위해 제거합니다. 때로는 비계를 그대로두면 테스트가 내러티브 역할을하는 데 도움이됩니다.


답변

나는 이미이 기술에 대해 읽었다 – 아마도 당신에게서 – 그러나 나는 그것을 사용하지 않는다; 주로 단위 테스트를 위해 트리플 A 양식에 익숙하기 때문입니다.

이제 호기심이 생기고 몇 가지 질문이 있습니다. 테스트를 어떻게 작성합니까,이 주장이 실패하도록 만들었습니까? 빨강-녹색-빨강-녹색-리 팩터주기를 따르거나 나중에 추가합니까?

코드를 리팩토링 한 후 가끔 실패합니까? 이것은 당신에게 무엇을 말합니까? 도움이 된 사례를 공유 할 수있을 것입니다. 감사.