簡體   English   中英

使用MOQ測試存儲庫

[英]Using MOQ to test a repository

我試圖使用MOQ測試存儲庫來模擬repo的行為。 我對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);
}

這個測試看起來不錯嗎?

[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());
}

你的方法很好,但我會調整一些東西。 我對您的測試和模擬組件進行了一些更改,您可以在下面看到。

單元測試

您在單元測試中的測試方法(見下文)與您在問題中定義的方法並不完全匹配。

單元測試方法調用:

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

測試方法:

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

我假設上面的方法是另一個類的一部分,我稱之為NotesHelper - 不是存儲庫調用的理想名稱,但它只是為了讓編譯工作。

我個人會將你的單元測試分成兩個獨立的單元測試。 一個用於驗證是否調用了所需的方法,另一個用於驗證是否已從集合中刪除了注釋。

我還創建了一個fakeSubmissionVersion,而不是創建一個模擬的SubmissionVersion。 這是因為SubmissionVersion中的例程可能不是可模擬的。 您還可以進行基於狀態的測試(首選)以確保版本.Notes.Remove(注意); 被稱為。

[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);
}

附加說明:同時提供描述性單元測試方法名稱可提高單元測試的可讀性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM