繁体   English   中英

如何在“告诉,不要问”跟随者课程中进行单元测试?

[英]How to unit-test in “tell, don't ask” follower classes?

我认为这个问题最好用一个例子来解释。

public class MyService {
    private OtherService theOther;
    public void setTheOther(OtherService srv) { theOther = srv; }

    public void myBusinessStuffFor(int id) {
        theOther.applyToAllWith(id, new OtherService.Action() {
            public void apply(Object whatever) {
                doTheHardBusinessStuffWith(whatever);
            }
        }
    }

    private void doTheHardBusinessStuffWith(Object whatever) {
        // here the business stuff provided by MyService
    }
}

public interface OtherService {
    void applyToAllWith(int id, Action action);

    public interface Action {
        void applyOn(Object whatever);
    }
}

我喜欢这种模式,因为它非常有凝聚力。 操作界面与其服务配对。 许多类中的业务逻辑并不杂乱。 子类只为操作提供数据,而不必繁忙。 我从这里采用它( http://jamesladdcode.com/?p=12 )。 问题是如果我模拟了otherService,我没有找到一个很好的解决方案来测试“doTheHardBusinessStuffWith(Object whatever)”方法中的行为。 使用模拟我必须关心如何调用业务方法。 但是我该怎么做呢 我使用了mockito并且已经使用ArgumentCapture进行了尝试。 但由于滥用ArgumentCapture,感觉不对。

我想知道MyService.myBusinessStuffFor(int id)类中使用的模式是否有名称(是策略模式)吗? 但我的主要问题是如何通过模拟OtherService使这段代码可测试?

在这种情况下,其他服务实际上不是商业服务。 它唯一的职责是从给定的ID中找到对象,并对这些对象应用给定的操作。 从功能上讲,这相当于以下代码:

Set<Object> objects = otherService.getObjectsWithId(id);
for (Object o : objects) {
    doTheHardBusinessStuffWith(o);
}

使doTheHardBusinessStuffWith受保护。 为此方法创建单元测试。 这是最重要的单元测试:测试业务逻辑的单元测试。

如果你真的想要对myBusinessStuffFor进行单元测试,你可以做的是创建一个模拟的OtherService(我的意思是你自己实现这个模拟),它是从一组对象构建的,并将其给定的动作应用于所有对象。集合。 创建MyService的部分模拟,其中模拟了doTheHardBusinessStuffWith方法,并注入了模拟OtherService。 在部分模拟上调用myBusinessStuffFor ,并验证是否已使用该组对象的每个对象调用doTheHardBusinessStuffWith

你谈论模仿OtherService。 我不知道你使用的是哪个模拟框架; 但是您应该能够创建一个模拟,它只调用传递给applyToAllWith方法的Action的applyOn方法,并将模拟对象作为参数传递。 例如,在mockito中,这将是这样的。

doAnswer( new Answer<Object>(){
    public Object answer( InvocationOnMock invocation ){
        ((Action) invocation.getArguments()[ 1 ]).applyOn( mockObject );
        return null;
}}).when( mockOtherService ).applyToAllWith( anyInt(), any( Action.class ));

其中mockOtherService是您为OtherService接口创建的模拟,而mockObject是您想要传递给doTheBusinessHardStuffWith

暂无
暂无

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

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