端到端或集成测试在 TDD 工作流中的什么位置?
Where do end-to-end or integration tests fit within a TDD worflow?
每个人都熟悉 TDD 的典型工作流程:编写一个失败的测试,通过编写足够的代码使测试通过,重构代码,然后重复。这通常用创造的“红色、绿色、重构”来捕捉。
TDD 工作流最自然地通过单元测试进行实践。但是,每个人也都知道这些还不够,一个好的代码库还应该包括集成和端到端测试。这些其他类型的测试能否或应该作为 TDD 工作流程的一部分实施?为什么或者为什么不?如果是这样,它们在典型敏捷团队的开发工作流实践中的什么位置?
是的,您可以使用 Outside-in TDD,从边界开始,针对 'surface area' 编写 coarse-grained 测试应用程序。之后,您可以通过集成和单元测试充实行为。
这是一个用 C# 编写的针对 REST API 的边界测试示例:
[Fact]
public async Task ReserveTableAtNono()
{
using var api = new SelfHostedApi();
var client = api.CreateClient();
var at = DateTime.Today.AddDays(434).At(20, 15);
var dto = Some.Reservation.WithDate(at).WithQuantity(6).ToDto();
var response = await client.PostReservation("Nono", dto);
await AssertRemainingCapacity(client, at, "Nono", 4);
await AssertRemainingCapacity(client, at, "Hipgnosta", 10);
}
示例取自我的博客post Self-hosted integration tests in ASP.NET.
我经常编写这样的测试,从边界开始,然后跟进像这样的单元测试:
[Fact]
public async Task PostToAbsentRestaurant()
{
var restaurantDB = new InMemoryRestaurantDatabase(Some.Restaurant);
var sut = new ReservationsController(
new SystemClock(),
restaurantDB,
new FakeDatabase());
var absentRestaurantId = 4;
var r = await restaurantDB.GetRestaurant(absentRestaurantId);
Assert.Null(r);
var actual =
await sut.Post(absentRestaurantId, Some.Reservation.ToDto());
Assert.IsAssignableFrom<NotFoundResult>(actual);
}
此测试绕过 HTTP 层,转而针对特定的 class (ReservationsController
) - 单元测试。
Nat Pryce 和 Steve Freeman 在他们 2009 年出版的书中对此技术进行了很好的描述 Growing Object-Oriented Software, Guided by Tests。
每个人都熟悉 TDD 的典型工作流程:编写一个失败的测试,通过编写足够的代码使测试通过,重构代码,然后重复。这通常用创造的“红色、绿色、重构”来捕捉。
TDD 工作流最自然地通过单元测试进行实践。但是,每个人也都知道这些还不够,一个好的代码库还应该包括集成和端到端测试。这些其他类型的测试能否或应该作为 TDD 工作流程的一部分实施?为什么或者为什么不?如果是这样,它们在典型敏捷团队的开发工作流实践中的什么位置?
是的,您可以使用 Outside-in TDD,从边界开始,针对 'surface area' 编写 coarse-grained 测试应用程序。之后,您可以通过集成和单元测试充实行为。
这是一个用 C# 编写的针对 REST API 的边界测试示例:
[Fact]
public async Task ReserveTableAtNono()
{
using var api = new SelfHostedApi();
var client = api.CreateClient();
var at = DateTime.Today.AddDays(434).At(20, 15);
var dto = Some.Reservation.WithDate(at).WithQuantity(6).ToDto();
var response = await client.PostReservation("Nono", dto);
await AssertRemainingCapacity(client, at, "Nono", 4);
await AssertRemainingCapacity(client, at, "Hipgnosta", 10);
}
示例取自我的博客post Self-hosted integration tests in ASP.NET.
我经常编写这样的测试,从边界开始,然后跟进像这样的单元测试:
[Fact]
public async Task PostToAbsentRestaurant()
{
var restaurantDB = new InMemoryRestaurantDatabase(Some.Restaurant);
var sut = new ReservationsController(
new SystemClock(),
restaurantDB,
new FakeDatabase());
var absentRestaurantId = 4;
var r = await restaurantDB.GetRestaurant(absentRestaurantId);
Assert.Null(r);
var actual =
await sut.Post(absentRestaurantId, Some.Reservation.ToDto());
Assert.IsAssignableFrom<NotFoundResult>(actual);
}
此测试绕过 HTTP 层,转而针对特定的 class (ReservationsController
) - 单元测试。
Nat Pryce 和 Steve Freeman 在他们 2009 年出版的书中对此技术进行了很好的描述 Growing Object-Oriented Software, Guided by Tests。