Как выполнить юнит-тестирование в классах последователей "скажи, не спрашивай"? - PullRequest
3 голосов
/ 20 января 2012

Я думаю, что проблему лучше всего объяснить на примере.

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). Проблема в том, что я не нашел хорошего решения для тестирования поведения в методе "doTheHardBusinessStuffWith (Object независимо от того, что))", если я издеваюсь над другим сервисом. все равно, как вызывается бизнес-метод. Но как я могу это сделать. Я использую mockito и уже пробовал его с ArgumentCapture. Но он не чувствует себя хорошо из-за злоупотребления ArgumentCapture.

Я хотел бы знать, имеет ли имя шаблон, используемый в классе MyService.myBusinessStuffFor (int id) (это шаблон стратегии)? Но мой главный вопрос - как сделать этот код тестируемым с помощью макета OtherService?

Ответы [ 2 ]

1 голос
/ 20 января 2012

В этом случае другой сервис не является бизнес-сервисом. Его единственная обязанность - найти объекты с заданным идентификатором и применить данное действие к этим объектам. Функционально это эквивалентно следующему коду:

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

Сделать doTheHardBusinessStuffWith защищенным. Создайте модульный тест для этого метода. Это самый важный модульный тест: тот, который проверяет бизнес-логику.

Если вы действительно хотите провести модульное тестирование myBusinessStuffFor, то вы можете создать макет OtherService (и я имею в виду реализовать этот макет самостоятельно, здесь), который построен из набора объектов и применяет данное действие для всех объектов в наборе. Создайте частичную имитацию MyService, где смоделирован метод doTheHardBusinessStuffWith, и который вводится вместе с вами. Вызовите myBusinessStuffFor для частичного макета и убедитесь, что doTheHardBusinessStuffWith был вызван с каждым объектом из набора объектов.

0 голосов
/ 20 января 2012

Вы говорите о издевательстве над OtherService.Я не знаю, какую систему насмешки вы используете;но у вас должна быть возможность создать макет, который просто вызывает метод applyOn действия, который передается методу applyToAllWith, передавая макет объекта в качестве аргумента.Например, в 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.

...