2013-10-24 4 views
3

MOQ를 사용하여 저장소를 테스트하여 저장소의 동작을 조롱하려고합니다. 나는 MOQ에 새로운 실패입니다. 그러니 제발 저와 함께하시기 바랍니다.MOQ를 사용하여 저장소를 테스트하십시오.

public static SubmissionVersion DeleteNote(IRepository repository, SubmissionVersion version, Guid noteId) 
{ 
    Note note = repository.GetById<Note>(noteId); 
    version.Notes.Remove(note); 
    repository.Save(version); 
    repository.Delete(note); 
    return repository.GetById<SubmissionVersion>(version.Id); 
} 

하는이 테스트는 OK 보입니까 :

는 다음과 같은 방법을 감안할 때?

[Fact] 
public void DeleteNoteV2() 
{ 
    // Arrange 
    var note = new Note{ Id = Guid.NewGuid()}; 

    var subVersion = new Mock<SubmissionVersion>(); 
    subVersion.Setup(x => x.Notes.Remove(note)); 

    var repo = new Mock<IRepository>(); 
    repo.Setup(x => x.GetById<Note>(note.Id)).Returns(note); 
    repo.Setup(x => x.GetById<SubmissionVersion>(It.IsAny<Guid?>())).Returns(subVersion.Object); 

    // Act 
    SubmissionVersion.DeleteNote(repo.Object, subVersion.Object, note.Id.Value); 

    // Assert 
    repo.Verify(x => x.GetById<Note>(note.Id), Times.Once()); 
    repo.Verify(x => x.Save(subVersion.Object), Times.Once()); 
    repo.Verify(x => x.Delete(note), Times.Once()); 

    subVersion.Verify(x => x.Notes.Remove(It.IsAny<Note>()), Times.Once()); 
} 
+0

내게 잘 어울리는데 – ayls

+1

작동하는지 테스트하는 좋은 방법 중 하나는 코드를 주석 처리하고 예상 한 지점에서 테스트가 실패했다는 것을 확인한 다음 코드를 다시 포함하고 통과하는지 확인하는 것입니다.이것이 TDD를 훌륭한 접근 방식으로 만드는 이유 중 하나입니다. TDD는 작성한 테스트를 검증하는 역할을하기 때문에 좋은 접근 방식입니다. –

답변

8

당신의 접근 방식은 좋지만, 나는 몇 가지를 조정할 것입니다. 아래에서 볼 수있는 테스트 및 조롱 구성 요소에 대한 몇 가지 변경 사항을 만들었습니다. 당신의 단위 테스트에서 테스트중인

단위 테스트

당신의 방법 (아래 참조), 정말 당신이 당신의 질문에 정의 된 방법과 일치하지 않습니다.

단위 시험 방법 전화 :

public static SubmissionVersion DeleteNote 
    (IRepository repository, SubmissionVersion version, Guid noteId) 

은 내가 NotesHelper로 불리는, 위의 방법은 다른 클래스의 일부 가정 - 아니 이상적인 이름 : 시험

SubmissionVersion.DeleteNote(repo.Object, subVersion.Object, note.Id.Value); 

방법 리포지토리 호출에 대해서는 컴파일 작업을 수행하는 것만으로 충분합니다.

개인적으로 단원 테스트를 2 개의 개별 단위 테스트로 분리합니다. 하나는 필요한 메서드가 호출되는지 여부를 확인하고 다른 하나는 노트가 컬렉션에서 제거되었는지 여부를 확인하는 것입니다.

또한 조롱받은 SubmissionVersion을 만드는 대신 fakeSubmissionVersion을 만들었습니다. SubmissionVersion 내의 루틴이 조롱 할 수 없기 때문입니다. 또한 버전을 확인하기 위해 상태 기반 테스팅 (선호)을 할 수 있습니다. 참고. 제거 (note); 가 호출되었습니다.

[Fact] 
public void DeleteNote_Deletion_VerifyExpectedMethodsInvokecOnlyOnce() 
{ 
    // Arrange 
    var note = new Note { Id = Guid.NewGuid() }; 
    var fakeSubmissionVersion = new SubmissionVersion() { Notes = new List<Note>() }; 
    var repo = new Mock<IRepository>(); 
    repo.Setup(x => x.GetById<Note>(It.IsAny<Guid>())).Returns(note); 

    // Act 
    NotesHelper.DeleteNote(repo.Object, fakeSubmissionVersion, note.Id.Value); 

    // Assert 
    repo.Verify(x => x.GetById<Note>(note.Id), Times.Once()); 
    repo.Verify(x => x.Save(fakeSubmissionVersion), Times.Once()); 
    repo.Verify(x => x.Delete(note), Times.Once()); 
} 

위의 테스트는 각 테스트를 자체 테스트로 정의하여 더욱 향상시킬 수 있습니다.

[Fact] 
public void DeleteNote_Deletion_VerifyDeleteMethodCalledOnlyOnce() 

이 방법은 하나의 테스트가 실패하면 정확히 어떤 메소드가 기대와 함께 호출되지 않았는지 알 수 있습니다. 위와 같이 여러 번 확인하는 경우 문제가 될 수 있습니다. 예를 들어 Save 메서드가 호출되지 않은 경우 Delete 메서드가 호출되었는지 여부를 알 수 없습니다. 이는 Save 메소드가 호출되지 않고 테스트 실행이 종료되었을 때 예외가 발생했기 때문입니다.

이렇게하면 테스트가 여러 번되지만 읽기 쉽고 유지 관리가 쉽습니다. 물론 일반 코드를 팩토리 또는 도우미 메서드로 리팩토링 할 수 있습니다.

[Fact] 
public void DeleteNote_RemoveNotes_ReturnsExpectedNotes() 
{ 
    // Arrange 
    var note = new Note { Id = Guid.NewGuid() }; 
    var fakeSubmissionVersion = new SubmissionVersion() { Notes = new List<Note>() { note } }; 
    var repo = new Mock<IRepository>(); 
    repo.Setup(x => x.GetById<Note>(It.IsAny<Guid>())).Returns(note); 

    // Act 
    NotesHelper.DeleteNote(repo.Object, fakeSubmissionVersion, note.Id.Value); 

    // Assert 
    Assert.AreEqual(0, fakeSubmissionVersion.Notes.Count); 
} 

추가 참고 사항 : 단원 테스트 방법 이름을 기술하면 단위 테스트의 가독성이 향상됩니다.

+0

아주 좋은 답변입니다! 통찰력에 감사드립니다! – Sam

+0

좀 더 설명해 주실 수 있겠습니까?'Unit Test에서 테스트중인 메소드 (아래 참조)는 질문에 정의한 메소드와 실제로 일치하지 않습니다. ' – Sam

+1

@Sam, prob 없음. 그게 당신의 질문에 대한 "다음과 같은 방법": public static SubmissionVersion DeleteNote (IRepository 저장소, SubmissionVersion 버전, Guid noteId) - 나는 이것이 당신이 테스트하는 메서드 (Test Under Method)라고 생각합니다. 그러나 테스트 대상 시스템 (System Under Test, SUT) 클래스가 무엇인지 명확하지 않았습니다. 또한 새로운 Mock ()이 있습니다. 그래서 당신의 SUT가 무엇인지 추론 할 수 없으므로 테스트 의도가 분명합니다. 그래서 SUT로 NotesHelper (이상적이지 않은)를 도입했습니다. – Spock

관련 문제