繁体   English   中英

领域驱动设计 - 可测试性和“新”关键字

[英]Domain Driven Design - testability and the “new” keyword

我一直在尝试在我的新项目中遵循域驱动的设计方法。 我一直使用Spring进行依赖注入,这很好地将我的应用程序代码与构造代码分开,然而,使用DDD我似乎总是有一个域对象想要创建另一个域对象,这两个域对象都有状态和行为。

例如,给定媒体文件,我们希望将其编码为不同的格式 - 媒体资产调用转码服务并接收回调:

class MediaAsset implements TranscodingResultListener {

    private NetworkLocation permanentStorage;
    private Transcoder transcoder;

    public void transcodeTo(Format format){
        transcoder.transcode(this,format);
    }

    public void onSuccessfulTranscode(TranscodeResult result){
        Rendition rendition = new Rendition(this, result.getPath(), result.getFormat());
        rendition.moveTo(permanentStorage);
    }

}

这引发了两个问题:

  • 如果再现需要一些依赖(比如MediaAsset需要一个“Transcoder”)并且我想使用类似Spring的东西来注入它们,那么我必须使用AOP才能运行我的程序,我不喜欢。
  • 如果我想要MediaAsset的单元测试来测试新格式是否被移动到临时存储,那么我该怎么做? 我无法模拟rendition类来验证它的方法被调用...将创建真正的Rendition类。

有一个工厂来创建这个类是我考虑过的,但是为了包含导致问题的“new”关键字,需要大量的代码开销。

这里有一种我想念的方法,还是我只是做错了?

我认为在这种情况下注入RenditionFactory是正确的方法。 我知道它需要额外的工作,但你也从你的班级中删除了SRP违规。 在业务逻辑中构建对象通常很诱人,但我的经验是,对象或对象的注入在100次中有99次得到回报。 特别是如果所提到的对象是复杂的,和/或如果它与系统资源交互。

我假设你的单元测试方法是MediaAsset测试MediaAsset 这样做,我认为工厂是常见的解决方案。

另一种方法是测试整个系统(或几乎整个系统)。 让您的测试访问外部接口[1](用户界面,Web服务接口等),并为系统访问的所有外部系统(数据库,文件系统,外部服务等)创建测试双精度。 然后让测试注入这些外部依赖项。

这样做,您可以让测试完全与行为有关。 测试与实现细节分离。 例如,您可以使用依赖注入来实现Rendition :测试不关心。 此外,您可能会发现MediaAssetRendition不是正确的概念[2],您可能需要将MediaAsset拆分为两个,并将其中的一半与Rendition合并。 同样,您可以在不担心测试的情况下完成此操作。

(免责声明:外层测试并不总是有效。有时你需要测试常见概念,这需要你编写微测试。然后你可能会再次遇到这个问题。)

[1]最佳级别实际上可能是“域界面”,低于用户界面的级别,您可以使用域语言而不是字符串和整数,并且您可以在这里谈论域操作而不是按钮点击和焦点事件。

[2]也许这实际上是你的问题: MediaAssetRendition是正确的概念吗? 如果你问你的域专家,他知道这些是什么吗? 如果没有,你真的在​​做DDD吗?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM