2015-08-08 2 views
1

Я пишу тестовые тесты конечных точек, и для большинства из них есть внешняя веб-служба, которую нужно издеваться, или пару из них.альтернатива оператору instanceof при указании mocks для нескольких веб-сервисов

Сначала я создавал макеты в тестах, которые были в порядке, когда в тесте на конечную точку использовалась только одна внешняя служба, создание макета было в основном одним лайнером.

Поскольку использование случаев стало более сложным, мне нужно было издеваться над несколькими сервисами и исключениями для одного теста конечных точек. Я создал эти штуки для фабрик за фабриками, которые расширяют единый заводский шаблон.

Внутри этой фабрики есть внутренний класс, который я использовал в качестве строителя для MockWebServiceServer.

protected class MultiStepMockBuilder { 

    private List<Object> mockActions = new ArrayList<Object>(); 
    private WebServiceGatewaySupport gatewaySupport; 

    protected MultiStepMockBuilder(WebServiceGatewaySupport gatewaySupport) { 

     this.gatewaySupport = gatewaySupport; 
    } 

    protected MultiStepMockBuilder exception(RuntimeException exception) { 

     mockActions.add(exception); 

     return this; 

    } 

    protected MultiStepMockBuilder resource(Resource resource) { 

     mockActions.add(resource); 

     return this; 
    } 

    protected MockWebServiceServer build() { 

     MockWebServiceServer server = MockWebServiceServer.createServer(gatewaySupport); 

     for(Object mock: mockActions) { 

      if (mock instanceof RuntimeException) { 

       server.expect(anything()).andRespond(withException((RuntimeException)mock)); 
      } 

      else if (mock instanceof Resource) 
      { 

       try 
       { 
        server.expect(anything()).andRespond(withSoapEnvelope((Resource) mock)); 

       } catch (IOException e) {e.printStackTrace();} 
      } 

      else 
       throw new RuntimeException("unusuported mock action"); 
     } 

     return server; 
    } 
    } 
} 

Так что я теперь сделать что-то вроде этого, чтобы создать макет:

return new MultiStepMockBuilder(gatewaySupport).resource(success).exception(new WebServiceIOException("reserve timeout")) 
               .resource(invalidMsisdn) 
               .build();  

Проблема у меня с этой реализации является зависимость от instanceof оператора, который я никогда не использовать за пределами equals.

Есть ли альтернативный способ экземпляра оператора в этом сценарии? Из вопросов по теме instanceof все утверждают, что их следует использовать только в пределах equals, и поэтому у меня есть ощущение, что это «грязное» решение.

Есть ли альтернатива оператору instanceof, в пределах весны или как другой дизайн, сохраняя при этом fluent interface для создания макетов?

ответ

1

Я не знаю Весны достаточно хорошо, чтобы комментировать именно эту область, но для меня это просто похоже на дизайн. Как правило, когда вы сталкиваетесь с использованием instanceof, это означает, что вам нужно знать тип, но у вас его нет. Как правило, нам может понадобиться рефакторинг, чтобы добиться более сплоченной конструкции, которая позволяет избежать такой проблемы.

Корень, где информация о типе теряется, находится в List от ложных действий, которые в настоящее время хранится только в качестве List из Object с. Один из способов помочь с этим - посмотреть тип List и рассмотреть, есть ли более лучший тип, который может быть сохранен в List, который может помочь нам позже. Таким образом, мы могли бы закончить с рефакторингом что-то вроде этого.

private List<MockAction> mockActions = new ArrayList<MockAction>(); 

Конечно, мы должны решить, какой MockAction на самом деле, как мы только что сделали это. Может быть, что-то вроде этого:

interface MockAction { 
    void performAction(MockWebServiceServer server); 
} 

Итак, мы только что создали этот MockAction интерфейс, и мы решили, что вместо того, чтобы вызывающий выполняющее действие - мы собираемся передать на сервер в него и спросить MockAction выполнять себя. Если мы это сделаем, то нет необходимости в instanceof - потому что конкретные типы MockAction s будут знать, что они содержат.

Итак, какие типы MockAction s нам нужны?

class ExceptionAction implements MockAction { 
    private final Exception exception; 

    private ExceptionAction(final Exception exception) { 
    this.exception = exception; 
    } 

    public void performAction(final MockWebServiceServer server) { 
    server.expect(anything()).andRespond(withException(exception); 
    } 

} 

class ResourceAction implements MockAction { 

    private final Resource resource; 

    private ResourceAction(final Resource resource) { 
    this.resource = resource; 
    } 

    public void performAction(final MockWebServiceServer server) { 
    /* I've left out the exception handling */ 
    server.expect(anything()).andRespond(withSoapEnvelope(resource)); 
    } 
} 

Хорошо, теперь мы дошли до этого момента, есть несколько свободных концов.

Мы по-прежнему добавляем исключения из списка MockAction s - но нам нужно изменить методы добавления, чтобы убедиться, что мы поместим правильную вещь в список. Новые версии этих методов может выглядеть примерно так:

protected MultiStepMockBuilder exception(RuntimeException exception) { 

    mockActions.add(new ExceptionAction(exception)); 

    return this; 

} 

protected MultiStepMockBuilder resource(Resource resource) { 

    mockActions.add(new ResourceAction(resource)); 

    return this; 
} 

Итак, теперь мы оставили наш интерфейс такой же, но мы оберточной ресурс или исключение, как они будут добавлены в список, так что у нас есть специфичность типов, которые нам нужны позже.

И наконец, нам нужно реорганизовать наш метод, который фактически вызывает вызовы, которые теперь выглядят примерно так: это намного проще и чище.

protected MockWebServiceServer build() { 
    MockWebServiceServer server = MockWebServiceServer.createServer(gatewaySupport); 

    for(MockAction action: mockActions) { 
     action.performAction(server); 
    } 
    return server; 
} 
+0

Это действительно хорошая идея, чтобы обернуть исключение и ресурс в контейнерах, которые реализуют общий интерфейс. Обычно у меня были собственные объекты, реализующие общий интерфейс, чтобы исключить экземпляр, но поскольку RuntimeException и ресурс java thingy, я не мог этого сделать. – John

Смежные вопросы