

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# Injeção de capacidade de teste e dependência
<a name="test"></a>

**Topics**
+ [Integração com o Spring](#test.spring)
+ [JUnit Integração](#test.junit)

A estrutura é projetada para ser amigável para inversão de controle (IoC). As implementações de atividades e de fluxo de trabalho assim como os operadores fornecidos pela estrutura e os objetos de contexto podem ser configurados e instanciados usando contêineres, como o Spring. Pronta para uso, a estrutura fornece integração com o Spring Framework. Além disso, a integração com JUnit foi fornecida para implementações de atividades e fluxos de trabalho de testes unitários. 

## Integração com o Spring
<a name="test.spring"></a>

O pacote de com.amazonaws.services.simpleworkflow.flow.spring contém classes que facilitam o uso do Spring Framework em seus aplicativos. Esses incluem operadores de atividades e de fluxo de trabalho com reconhecimento de um escopo personalizado do Spring: `WorkflowScope`, `SpringWorkflowWorker` e `SpringActivityWorker`. Essas classes permitem configurar suas implementações de fluxo de trabalho e de atividade bem como os operadores totalmente por meio do Spring.

### WorkflowScope
<a name="test.workflowscope"></a>

`WorkflowScope` é uma implementação de Escopo do Spring fornecida pela estrutura. O escopo permite criar objetos no contêiner do Spring cujo tempo de vida tem o escopo de uma tarefa de decisão. Os beans nesse escopo são instanciados sempre que uma nova tarefa de decisão é recebida pelo operador. Você deve usar esse escopo para beans de implementação de fluxo de trabalho e todos os outros beans dos quais ele depende. Os escopos singleton e de protótipo fornecidos pelo Spring não devem ser usados para beans de implementação de fluxo de trabalho porque a estrutura exige que um novo bean seja criado para cada tarefa de decisão. Não fazer isso resultará em comportamento inesperado.

O exemplo a seguir mostra um trecho de código de configuração do Spring que registra o `WorkflowScope` e, em seguida, usa-o para configurar um bean de implementação de fluxo de trabalho e um bean de cliente de atividade.

```
<!-- register AWS Flow Framework for Java WorkflowScope -->
   <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
      <property name="scopes">
       <map>
         <entry key="workflow">
          <bean class="com.amazonaws.services.simpleworkflow.flow.spring.WorkflowScope" />
         </entry>
       </map>
      </property>
   </bean>

   <!-- activities client -->
   <bean id="activitiesClient" class="aws.flow.sample.MyActivitiesClientImpl" scope="workflow">
   </bean>

   <!-- workflow implementation -->
   <bean id="workflowImpl" class="aws.flow.sample.MyWorkflowImpl" scope="workflow">
      <property name="client" ref="activitiesClient"/>
      <aop:scoped-proxy proxy-target-class="false" />
   </bean>
```

A linha de configuração: `<aop:scoped-proxy proxy-target-class="false" />`, usada na configuração do bean `workflowImpl`, é necessária porque o `WorkflowScope` não oferece suporte a proxy usando CGLIB. Você deve usar essa configuração para qualquer bean no `WorkflowScope` que esteja conectado a outro bean em outro escopo. Nesse caso, o bean `workflowImpl` precisa ser conectado a um bean de operador de fluxo de trabalho em escopo singleton (consulte o exemplo completo a seguir).

Saiba mais sobre o uso de escopos personalizados na documentação do Spring Framework.

### Operadores com reconhecimento do Spring
<a name="test.springworkers"></a>

Ao usar o Spring, você deve usar as classes de operador com reconhecimento do Spring fornecidas pela estrutura: `SpringWorkflowWorker` e `SpringActivityWorker`. Esses operadores podem ser injetados em seu aplicativo usando o Spring, conforme mostrado no exemplo a seguir. Os operadores com reconhecimento do Spring implementam a interface `SmartLifecycle` do Spring e, por padrão, começam a pesquisar tarefas automaticamente quando o contexto do Spring é inicializado. Você pode desativar essa funcionalidade definindo a propriedade `disableAutoStartup` do operador como `true`.

O exemplo a seguir mostra como configurar um agente de decisão. O exemplo usa as interfaces `MyActivities` e `MyWorkflow` (não mostradas aqui) e as implementações correspondentes, `MyActivitiesImpl` e `MyWorkflowImpl`. As interfaces e as implementações de cliente geradas são `MyWorkflowClient`/`MyWorkflowClientImpl` e `MyActivitiesClient`/`MyActivitiesClientImpl` (também não mostradas aqui).

O cliente de atividades é injetado na implementação do fluxo de trabalho usando o recurso de conexão automática do Spring:

```
public class MyWorkflowImpl implements MyWorkflow {
   @Autowired
   public MyActivitiesClient client;

   @Override
   public void start() {
      client.activity1();
   }
}
```

A configuração do agente de decisão do Spring é a seguinte:

```
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
   http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <!-- register custom workflow scope -->
   <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
      <property name="scopes">
       <map>
         <entry key="workflow">
          <bean class="com.amazonaws.services.simpleworkflow.flow.spring.WorkflowScope" />
         </entry>
       </map>
      </property>
   </bean>
   <context:annotation-config/>

   <bean id="accesskeys" class="com.amazonaws.auth.BasicAWSCredentials">
      <constructor-arg value="{AWS.Access.ID}"/>
      <constructor-arg value="{AWS.Secret.Key}"/>
   </bean>

   <bean id="clientConfiguration" class="com.amazonaws.ClientConfiguration">
      <property name="socketTimeout" value="70000" />
   </bean>

   <!-- Amazon SWF client -->
   <bean id="swfClient"
      class="com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClient">
      <constructor-arg ref="accesskeys" />
      <constructor-arg ref="clientConfiguration" />
      <property name="endpoint" value="{service.url}" />
   </bean>

   <!-- activities client -->
   <bean id="activitiesClient" class="aws.flow.sample.MyActivitiesClientImpl" scope="workflow">
   </bean>

   <!-- workflow implementation -->
   <bean id="workflowImpl" class="aws.flow.sample.MyWorkflowImpl" scope="workflow">
      <property name="client" ref="activitiesClient"/>
      <aop:scoped-proxy proxy-target-class="false" />
   </bean>

   <!-- workflow worker -->
   <bean id="workflowWorker"
      class="com.amazonaws.services.simpleworkflow.flow.spring.SpringWorkflowWorker">
      <constructor-arg ref="swfClient" />
      <constructor-arg value="domain1" />
      <constructor-arg value="tasklist1" />
      <property name="registerDomain" value="true" />
      <property name="domainRetentionPeriodInDays" value="1" />
      <property name="workflowImplementations">
         <list>
            <ref bean="workflowImpl" />
         </list>
      </property>
   </bean>
</beans>
```

Como o `SpringWorkflowWorker` está totalmente configurado no Spring e inicia automaticamente a pesquisa quando o contexto do Spring é inicializado, o processo de hospedagem para o decisor é simples:

```
public class WorkflowHost {
   public static void main(String[] args){
      ApplicationContext context
          = new FileSystemXmlApplicationContext("resources/spring/WorkflowHostBean.xml");
      System.out.println("Workflow worker started");
   }
}
```

Da mesma forma, o operador de atividades pode ser configurado da seguinte maneira:

```
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
   http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <!-- register custom scope -->
   <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
      <property name="scopes">
         <map>
            <entry key="workflow">
               <bean
                  class="com.amazonaws.services.simpleworkflow.flow.spring.WorkflowScope" />
            </entry>
         </map>
      </property>
   </bean>

   <bean id="accesskeys" class="com.amazonaws.auth.BasicAWSCredentials">
      <constructor-arg value="{AWS.Access.ID}"/>
      <constructor-arg value="{AWS.Secret.Key}"/>
   </bean>

   <bean id="clientConfiguration" class="com.amazonaws.ClientConfiguration">
      <property name="socketTimeout" value="70000" />
   </bean>

   <!-- Amazon SWF client -->
   <bean id="swfClient"
      class="com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClient">
      <constructor-arg ref="accesskeys" />
      <constructor-arg ref="clientConfiguration" />
      <property name="endpoint" value="{service.url}" />
   </bean>

   <!-- activities impl -->
   <bean name="activitiesImpl" class="asadj.spring.test.MyActivitiesImpl">
   </bean>

   <!-- activity worker -->
   <bean id="activityWorker"
      class="com.amazonaws.services.simpleworkflow.flow.spring.SpringActivityWorker">
      <constructor-arg ref="swfClient" />
      <constructor-arg value="domain1" />
      <constructor-arg value="tasklist1" />
      <property name="registerDomain" value="true" />
      <property name="domainRetentionPeriodInDays" value="1" />
      <property name="activitiesImplementations">
         <list>
            <ref bean="activitiesImpl" />
         </list>
      </property>
   </bean>
</beans>
```

O processo de host do operador de atividades é semelhante ao do agente de decisão:

```
public class ActivityHost {
   public static void main(String[] args) {
      ApplicationContext context = new FileSystemXmlApplicationContext(
      "resources/spring/ActivityHostBean.xml");
      System.out.println("Activity worker started");
   }
}
```

### Injeção do contexto de decisão
<a name="test.injectdecision"></a>

Se a implementação do fluxo de trabalho depender dos objetos do contexto, você também poderá injetá-los facilmente por meio do Spring. A estrutura registra automaticamente os beans relacionados ao contexto no contêiner do Spring. Por exemplo, no trecho de código a seguir, os vários objetos do contexto foram conectados automaticamente. Não é necessária nenhuma outra configuração do Spring para os objetos de contexto.

```
public class MyWorkflowImpl implements MyWorkflow {
   @Autowired
   public MyActivitiesClient client;
   @Autowired
   public WorkflowClock clock;
   @Autowired
   public DecisionContext dcContext;
   @Autowired
   public GenericActivityClient activityClient;
   @Autowired
   public GenericWorkflowClient workflowClient;
   @Autowired
   public WorkflowContext wfContext;
   @Override
   public void start() {
      client.activity1();
   }
}
```

Para configurar os objetos de contexto na implementação do fluxo de trabalho por meio da configuração XML do Spring, use os nomes de beans declarados na classe `WorkflowScopeBeanNames` no pacote com.amazonaws.services.simpleworkflow.flow.spring. Por exemplo:

```
<!-- workflow implementation -->
<bean id="workflowImpl" class="asadj.spring.test.MyWorkflowImpl" scope="workflow">
   <property name="client" ref="activitiesClient"/>
   <property name="clock" ref="workflowClock"/>
   <property name="activityClient" ref="genericActivityClient"/>
   <property name="dcContext" ref="decisionContext"/>
   <property name="workflowClient" ref="genericWorkflowClient"/>
   <property name="wfContext" ref="workflowContext"/>
   <aop:scoped-proxy proxy-target-class="false" />
</bean>
```

Como alternativa, você pode injetar um `DecisionContextProvider` no bean de implementação de fluxo de trabalho e usá-lo para criar o contexto. Isso pode ser útil se você desejar fornecer implementações personalizadas de provedor e do contexto.

### Injeção de recursos em atividades
<a name="test.injectresource"></a>

Você pode instanciar e configurar implementações de atividades usando um contêiner de inversão de controle (IoC) e injetar recursos facilmente, como conexões de banco de dados, declarando-os como propriedades da classe de implementação da atividade. Normalmente, esses recursos terão escopos singletons. Observe que as implementações de atividades são chamadas por operadores de atividades em vários threads. Portanto, o acesso aos recursos compartilhados deve ser sincronizado.

## JUnit Integração
<a name="test.junit"></a>

A estrutura fornece JUnit extensões e implementações de teste dos objetos de contexto, como um relógio de teste, que você pode usar para escrever e executar testes de JUnit unidade. Com essas extensões, você pode testar a implementação do fluxo de trabalho localmente em linha.

### Criação de um teste de unidade simples
<a name="test.junit.simple"></a>

 Para escrever testes para seu fluxo de trabalho, use a classe `WorkflowTest` no pacote com.amazonaws.services.simpleworkflow.flow.junit. Essa classe é uma JUnit `MethodRule` implementação específica da estrutura e executa seu código de fluxo de trabalho localmente, chamando atividades em linha em vez de usar o Amazon SWF. Isso fornece a flexibilidade de executar testes quantas vezes forem desejadas sem incorrer em encargos. 

Para usar essa classe, simplesmente declare um campo do tipo `WorkflowTest` e anote-o com a anotação `@Rule`. Antes de executar seus testes, crie um novo objeto `WorkflowTest` e adicione suas implementações de atividades e de fluxo de trabalho a ele. Em seguida, você pode usar a fábrica de cliente de fluxo de trabalho gerada para criar e iniciar uma execução do fluxo de trabalho. A estrutura também fornece um JUnit executor personalizado,`FlowBlockJUnit4ClassRunner`, que você deve usar para seus testes de fluxo de trabalho. Por exemplo: 

```
@RunWith(FlowBlockJUnit4ClassRunner.class)
public class BookingWorkflowTest {

    @Rule
    public WorkflowTest workflowTest = new WorkflowTest();

    List<String> trace;

    private BookingWorkflowClientFactory workflowFactory
         = new BookingWorkflowClientFactoryImpl();

    @Before
    public void setUp() throws Exception {
        trace = new ArrayList<String>();
        // Register activity implementation to be used during test run
        BookingActivities activities = new BookingActivitiesImpl(trace);
        workflowTest.addActivitiesImplementation(activities);
        workflowTest.addWorkflowImplementationType(BookingWorkflowImpl.class);
    }

    @After
    public void tearDown() throws Exception {
        trace = null;
    }

    @Test
    public void testReserveBoth() {
        BookingWorkflowClient workflow = workflowFactory.getClient();
        Promise<Void> booked = workflow.makeBooking(123, 345, true, true);
        List<String> expected = new ArrayList<String>();
        expected.add("reserveCar-123");
        expected.add("reserveAirline-123");
        expected.add("sendConfirmation-345");
        AsyncAssert.assertEqualsWaitFor("invalid booking", expected, trace, booked);
    }
}
```

Você também pode especificar uma lista de tarefas separada para cada implementação de atividade adicionada ao `WorkflowTest`. Por exemplo, se tiver uma implementação de fluxo de trabalho que programa atividades em listas de tarefas específicas ao host, você poderá registrar a atividade na lista de tarefas de cada host:

```
for (int i = 0; i < 10; i++) {
    String hostname = "host" + i;
    workflowTest.addActivitiesImplementation(hostname,
                                             new ImageProcessingActivities(hostname));
}
```

Observe que o código em `@Test` é assíncrono. Portanto, você deve usar o cliente de fluxo de trabalho assíncrono para iniciar uma execução. Para verificar os resultados do teste, uma classe auxiliar `AsyncAssert` também é fornecida. Essa classe permite que você aguarde que as promessas estejam prontas antes de verificar os resultados. Neste exemplo, esperamos que o resultado da execução do fluxo de trabalho esteja pronto antes de verificar a saída do teste.

Se você estiver usando o Spring, a classe `SpringWorkflowTest` pode ser usada em vez da classe `WorkflowTest`. O `SpringWorkflowTest` oferece propriedades que você pode usar para configurar facilmente por meio de implementações de atividade e de fluxo de configuração do Spring. Assim como os operadores com reconhecimento do Spring, você deve usar o `WorkflowScope` para configurar beans de implementação de fluxo de trabalho. Isso garante que um novo bean de implementação de fluxo de trabalho seja criado para cada tarefa de decisão. Certifique-se de configurar esses beans com a proxy-target-class configuração scoped-proxy definida como. `false` Consulte a seção Integração com o Spring para obter mais detalhes. A configuração de exemplo do Spring mostrada na seção Integração com o Spring pode ser alterada para testar o fluxo de trabalho usando o `SpringWorkflowTest`: 

```
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans ht
tp://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframe
work.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

  <!-- register custom workflow scope -->
  <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
      <map>
        <entry key="workflow">
          <bean
            class="com.amazonaws.services.simpleworkflow.flow.spring.WorkflowScope" />
        </entry>
      </map>
    </property>
  </bean>
  <context:annotation-config />
  <bean id="accesskeys" class="com.amazonaws.auth.BasicAWSCredentials">
    <constructor-arg value="{AWS.Access.ID}" />
    <constructor-arg value="{AWS.Secret.Key}" />
  </bean>
  <bean id="clientConfiguration" class="com.amazonaws.ClientConfiguration">
    <property name="socketTimeout" value="70000" />
  </bean>

  <!-- Amazon SWF client -->
  <bean id="swfClient"
    class="com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClient">
    <constructor-arg ref="accesskeys" />
    <constructor-arg ref="clientConfiguration" />
    <property name="endpoint" value="{service.url}" />
  </bean>

  <!-- activities client -->
  <bean id="activitiesClient" class="aws.flow.sample.MyActivitiesClientImpl"
    scope="workflow">
  </bean>

  <!-- workflow implementation -->
  <bean id="workflowImpl" class="aws.flow.sample.MyWorkflowImpl"
    scope="workflow">
    <property name="client" ref="activitiesClient" />
    <aop:scoped-proxy proxy-target-class="false" />
  </bean>

  <!-- WorkflowTest -->
  <bean id="workflowTest"
    class="com.amazonaws.services.simpleworkflow.flow.junit.spring.SpringWorkflowTest">
    <property name="workflowImplementations">
      <list>
        <ref bean="workflowImpl" />
      </list>
    </property>
    <property name="taskListActivitiesImplementationMap">
      <map>
        <entry>
          <key>
            <value>list1</value>
          </key>
          <ref bean="activitiesImplHost1" />
        </entry>
      </map>
    </property>
  </bean>
</beans>
```

#### Implementações de atividades fictícias
<a name="test.junit.mockactivity"></a>

Você pode usar as implementações de atividades reais durante o teste, mas se desejar executar testes de unidade apenas da lógica do fluxo de trabalho, você deve usar atividades fictícias. Isso pode ser feito fornecendo uma implementação fictícia da interface de atividades para a classe `WorkflowTest`. Por exemplo: 

```
@RunWith(FlowBlockJUnit4ClassRunner.class)
public class BookingWorkflowTest {

    @Rule
    public WorkflowTest workflowTest = new WorkflowTest();

    List<String> trace;

    private BookingWorkflowClientFactory workflowFactory
         = new BookingWorkflowClientFactoryImpl();

    @Before
    public void setUp() throws Exception {
        trace = new ArrayList<String>();
        // Create and register mock activity implementation to be used during test run
        BookingActivities activities = new BookingActivities() {

            @Override
            public void sendConfirmationActivity(int customerId) {
                trace.add("sendConfirmation-" + customerId);
            }

            @Override
            public void reserveCar(int requestId) {
                trace.add("reserveCar-" + requestId);
            }

            @Override
            public void reserveAirline(int requestId) {
                trace.add("reserveAirline-" + requestId);
            }
        };
        workflowTest.addActivitiesImplementation(activities);
        workflowTest.addWorkflowImplementationType(BookingWorkflowImpl.class);
    }

    @After
    public void tearDown() throws Exception {
        trace = null;
    }

    @Test
    public void testReserveBoth() {
        BookingWorkflowClient workflow = workflowFactory.getClient();
        Promise<Void> booked = workflow.makeBooking(123, 345, true, true);
        List<String> expected = new ArrayList<String>();
        expected.add("reserveCar-123");
        expected.add("reserveAirline-123");
        expected.add("sendConfirmation-345");
        AsyncAssert.assertEqualsWaitFor("invalid booking", expected, trace, booked);
    }
}
```

Como alternativa, você pode fornecer uma implementação fictícia do cliente de atividades e injetá-la em sua implementação de fluxo de trabalho.

### Teste de objetos de contexto
<a name="test.junit.objects"></a>

Se a implementação do seu fluxo de trabalho depender dos objetos de contexto do framework (por exemplo, o `DecisionContext`), você não precisará fazer nada de especial para testar esses fluxos de trabalho. Quando um teste é executado por meio do `WorkflowTest`, ele injeta automaticamente objetos de contexto de teste. Quando a implementação do seu fluxo de trabalho acessar os objetos de contexto (por exemplo, usando `DecisionContextProviderImpl`), ela obterá a implementação de teste. Você pode manipular esses objetos de contexto de teste no código de teste (método `@Test`) para criar casos de teste interessantes. Por exemplo, se o fluxo de trabalho criar um temporizador, você poderá fazer com que o temporizador seja acionado chamando o método `clockAdvanceSeconds` na classe `WorkflowTest` para adiantar a hora do relógio. Você também pode acelerar o relógio para fazer com que os temporizadores sejam acionados antes do que seriam normalmente usando a propriedade `ClockAccelerationCoefficient` no `WorkflowTest`. Por exemplo, se o fluxo de trabalho criar um temporizador para uma hora, você poderá definir o `ClockAccelerationCoefficient` como 60 para fazer com que o temporizador acione em um minuto. Por padrão, o `ClockAccelerationCoefficient` é definido como 1. 

Para obter mais detalhes sobre os pacotes com.amazonaws.services.simpleworkflow.flow.test and com.amazonaws.services.simpleworkflow.flow.junit, consulte a documentação do AWS SDK para Java . 