Sam*_*Sam 4 c# unit-testing moq xunit xunit.net
我试图使用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);
}
Run Code Online (Sandbox Code Playgroud)
这个测试看起来不错吗?
[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());
}
Run Code Online (Sandbox Code Playgroud)
你的方法很好,但我会调整一些东西.我对您的测试和模拟组件进行了一些更改,您可以在下面看到.
单元测试
您在单元测试中的测试方法(见下文)与您在问题中定义的方法并不完全匹配.
单元测试方法调用:
SubmissionVersion.DeleteNote(repo.Object, subVersion.Object, note.Id.Value);
Run Code Online (Sandbox Code Playgroud)
测试方法:
public static SubmissionVersion DeleteNote
(IRepository repository, SubmissionVersion version, Guid noteId)
Run Code Online (Sandbox Code Playgroud)
我假设上面的方法是另一个类的一部分,我称之为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());
}
Run Code Online (Sandbox Code Playgroud)
通过在自己的测试中定义每个验证,可以进一步改进上述测试.
[Fact]
public void DeleteNote_Deletion_VerifyDeleteMethodCalledOnlyOnce()
Run Code Online (Sandbox Code Playgroud)
这样,如果一个测试失败,我们就会确切地知道哪个方法没有被期望调用.有时,如上所述进行多次验证可能会有问题.例如,如果尚未调用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);
}
Run Code Online (Sandbox Code Playgroud)
附加说明:同时提供描述性单元测试方法名称可提高单元测试的可读性.
| 归档时间: |
|
| 查看次数: |
15678 次 |
| 最近记录: |