gpt4 book ai didi

c# - 单元测试的可重用设置

转载 作者:行者123 更新时间:2023-11-30 20:01:04 25 4
gpt4 key购买 nike

我正在使用 xUnit 和 Moq 编写我的单元测试,我在各种测试中有很多重复代码,我想将它们提取成某种可重用的方式。

重复代码

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

鉴于以下测试,我怎样才能清理它们以免出现太多重复?

[Fact]
public void Should_CallRepoGetNoteByIdOnce()
{
// 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());
}

[Fact]
public void Should_CallSubmissionVerionNotesRemoveOnce()
{
// 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
subVersion.Verify(x => x.Notes.Remove(note), Times.Once());
}

[Fact]
public void Should_CallRepoSaveSubmissionVersionOnce()
{
// 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.Save(subVersion.Object), Times.Once());
}

[Fact]
public void Should_CallRepoDeleteNoteOnce()
{
// 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.Delete(note), Times.Once());
}

[Fact]
public void Should_CallRepoGetSubmissionVersionByIdOnce()
{
// 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<SubmissionVersion>(subVersion.Object.Id), Times.Once());
}

[Fact]
public void Should_RemoveNotesFromSubmissionVersion()
{
// Arrange
var repo = new CompositeRepository().GenerateCompositeRepository<Guid?>(typeof(SubmissionVersion), typeof(Note));
var subVersion = new SubmissionVersion { Id = Guid.NewGuid() };
var note = new Note { Id = Guid.NewGuid(), Content = "Test Note" };

repo.Save(note);
subVersion.Notes.Add(note);

// Act
subVersion.Notes.ToList().ForEach(x => SubmissionVersion.DeleteNote(repo, subVersion, x.Id.Value));

// Assert
Assert.Null(repo.GetById<Note>(note.Id));
}

有什么建议/模式是最佳实践吗?

最佳答案

我通常通过制作一个单元测试上下文对象来解决这个问题,该对象将可重用模拟公开为公共(public)属性。该对象将在内部设置公共(public)模拟并将它们公开为公共(public)属性。您可以在此类中定义许多可重用的模拟。

例如:

public class UnitTestContext
{

public Mock<IRepository> Repo {get;set;}


public UnitTestContext()
{
// create suitable note / subversion objects
// either by passing them in or new-ing them up directly with default values.
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);

}
}

然后测试可以创建一个实例:

[Fact]
public void Some_Test_In_Need_Of_A_Mocked_Repository()
{
var ctx = new UnitTestContext();

SubmissionVersion.DeleteNote(ctx.Repo.Object, subVersion.Object, note.Id.Value);
}

我更喜欢这种方法,而不是将模拟定义为测试类中的成员,因为 UnitTestContext 可跨测试类重用。

如果在返回值方面需要更大的灵 active ,您还可以在构造模拟时将对象传递给上下文。您还可以通过 Repo 属性添加到类外部的模拟。

关于c# - 单元测试的可重用设置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19598770/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com