为了得到一个具体的例子,我有PromoCode
聚合根,它由PromoCodeUsage
实体组成,仅由该AR控制,因此AR上的某些方法只被委托给该实体,如:
public function useFor(Order $order): void
{
$this->promoCodeUsage->useFor($order);
}
其中一些部分被委派,如:
public function applyFor(Order $order): void
{
if (!$this->published) {
throw new NotPublishedPromoCodeCanNotBeApplied();
}
$this->promoCodeUsage->applyFor($order);
}
我的测试套件完全涵盖了所有PromoCode
行为,包括PromoCodeUsage
功能,因为在那次迭代中没有PromoCodeUsage
并且所有逻辑都混合在PromoCode
中。然后我将一些逻辑重构为PromoCodeUsage
。这个PromoCode
的测试套件有很多测试,我很高兴我也可以将它拆分(但是在拆分实体之后它也运行良好)。所以我创建了另一个测试套件(PromoCodeUsageTest
),在那里我从PromoCode移动了部分测试。
但是PromoCodeUsageTest
正在通过PromoCodeUsage
的行为测试PromoCode
实体,就像在拆分前的原始测试一样。他们没有直接接触PromoCodeUsage
。现在我有PromoCodeTest
套房:
和PromoCodeUsageTest套件:
但它有点奇怪,1)在PromoCodeTest
我省略了一些测试(在其他地方)和2)在PromoCodeUsageTest
我实际上没有触及PromoCodeUsage
实体。 3)我使用Roy Osherove的测试命名模板,我不知道我应该在测试名称中使用什么方法名称 - 来自PromoCode或PromoCodeUsage?在我的情况下,它们是相同的,但它们可能不同,这个想法闻起来。
如果我重写PromoCodeUsageTest
来直接测试PromoCodeUsage
实体,我最终会在PromoCode
上找到一些未被发现的方法(只是委托给PromoCodeUsage
)。因此,我回到了通过PromoCodeUsage
AR测试PromoCode
的方法。
Bob叔叔(和其他人)说测试行为是一种好习惯,而不是API。我的方法是否符合要求?
因为我的方法感觉有些气味,你呢?怎么做得更好?
答案 0 :(得分:2)
考虑行为是正确的。我假设聚合的所有行为都是通过聚合根公开的,因此通过根进行测试是有意义的。我建议你将测试命名为描述他们正在测试的行为。不要在测试名称中使用方法名称,因为这些名称可能会更改 - 这会将测试名称与生产代码的内部实现联系起来。
如果测试类变得非常大,那么将它分成更小的类是有意义的 - 没有规则要求测试类和生产类之间必须有1:1的关系。但是,这可能表明您的班级以及此案例中的汇总可能会承担太多责任,可能会分成更小的部分。
答案 1 :(得分:1)
我倾向于将Aggregates视为状态机并相应地测试它们。
重要的不在于测试所在的测试文件,而是测试PromoCode
聚合的所有可能结果状态,具体取决于您正在执行的启动状态和促销代码使用/应用程序的类型。
当然,这可能需要在依赖实体中深入研究聚合的内容。如果你更容易在其他测试类中放入所有Asserts看PromoCodeUsage
的测试,那么就好了,只要测试名称反映域而不是一些技术细节。