简体   繁体   English

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

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

I have been trying to follow a domain driven design approach in my new project. 我一直在尝试在我的新项目中遵循域驱动的设计方法。 I have always generally used Spring for dependency injection, which nicely separates my application code from the construction code, however, with DDD I always seem to have one domain object wanting to create another domain object, both of which have state and behaviour. 我一直使用Spring进行依赖注入,这很好地将我的应用程序代码与构造代码分开,然而,使用DDD我似乎总是有一个域对象想要创建另一个域对象,这两个域对象都有状态和行为。

For example, given a media file, we want to encode it to a different format - the media asset calls on a transcode service and receives a callback: 例如,给定媒体文件,我们希望将其编码为不同的格式 - 媒体资产调用转码服务并接收回调:

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

}

Which throws two problems: 这引发了两个问题:

  • If the rendition needs some dependencies (like the MediaAsset requires a "Transcoder") and I want to use something like Spring to inject them, then I have to use AOP in order for my program to run, which I don't like. 如果再现需要一些依赖(比如MediaAsset需要一个“Transcoder”)并且我想使用类似Spring的东西来注入它们,那么我必须使用AOP才能运行我的程序,我不喜欢。
  • If I want a unit test for MediaAsset that tests that a new format is moved to temporary storage, then how do I do that? 如果我想要MediaAsset的单元测试来测试新格式是否被移动到临时存储,那么我该怎么做? I cannot mock the rendition class to verify that it had its method called... the real Rendition class will be created. 我无法模拟rendition类来验证它的方法被调用...将创建真正的Rendition类。

Having a factory to create this class is something that I've considered, but it is a lot of code overhead just to contain the "new" keyword which causes the problems. 有一个工厂来创建这个类是我考虑过的,但是为了包含导致问题的“new”关键字,需要大量的代码开销。

Is there an approach here that I am missing, or am I just doing it all wrong? 这里有一种我想念的方法,还是我只是做错了?

I think that the injection of a RenditionFactory is the right approach in this case. 我认为在这种情况下注入RenditionFactory是正确的方法。 I know it requires extra work, but you also remove a SRP violation from your class. 我知道它需要额外的工作,但你也从你的班级中删除了SRP违规。 It is often tempting to construct objects inside business logic, but my experience is that injection of the object or a objectfactory pays off 99 out of 100 times. 在业务逻辑中构建对象通常很诱人,但我的经验是,对象或对象的注入在100次中有99次得到回报。 Especially if the mentioned object is complex, and/or if it interacts with system resources. 特别是如果所提到的对象是复杂的,和/或如果它与系统资源交互。

I assume your approach for unit testing is to test the MediaAsset in isolation. 我假设你的单元测试方法是MediaAsset测试MediaAsset Doing this, I think a factory is the common solution. 这样做,我认为工厂是常见的解决方案。

Another approach is to test the whole system (or almost the whole system). 另一种方法是测试整个系统(或几乎整个系统)。 Let your test access the outer interface[1] (user interface, web service interface, etc) and create test doubles for all external systems that the system accesses (database, file system, external services, etc). 让您的测试访问外部接口[1](用户界面,Web服务接口等),并为系统访问的所有外部系统(数据库,文件系统,外部服务等)创建测试双精度。 Then let the test inject these external dependencies. 然后让测试注入这些外部依赖项。

Doing this, you can let the tests be all about behaviour. 这样做,您可以让测试完全与行为有关。 The tests become decoupled from implementation details. 测试与实现细节分离。 For instance, you can use dependency injection for Rendition , or not: the tests don't care. 例如,您可以使用依赖注入来实现Rendition :测试不关心。 Also, you might discover that MediaAsset and Rendition are not the correct concepts[2], and you might need to split MediaAsset in two and merge half of it with Rendition . 此外,您可能会发现MediaAssetRendition不是正确的概念[2],您可能需要将MediaAsset拆分为两个,并将其中的一半与Rendition合并。 Again, you can do it without worrying about the tests. 同样,您可以在不担心测试的情况下完成此操作。

(Disclaimer: Testing on the outer level does not always work. Sometimes you need to test common concepts, which requires you to write micro tests. And then you might run into this problem again.) (免责声明:外层测试并不总是有效。有时你需要测试常见概念,这需要你编写微测试。然后你可能会再次遇到这个问题。)

[1] The best level might actually be a "domain interface", a level below the user interface where you can use the domain language instead of strings and integers, and where you can talk domain actions instead of button clicks and focus events. [1]最佳级别实际上可能是“域界面”,低于用户界面的级别,您可以使用域语言而不是字符串和整数,并且您可以在这里谈论域操作而不是按钮点击和焦点事件。

[2] Perhaps this is actually your problem: Are MediaAsset and Rendition the correct concepts? [2]也许这实际上是你的问题: MediaAssetRendition是正确的概念吗? If you ask your domain expert, does he know what these are? 如果你问你的域专家,他知道这些是什么吗? If not, are you really doing DDD? 如果没有,你真的在​​做DDD吗?

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

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