Pergunta

estamos usando Spring para os meus propósitos de aplicação, e framework de testes da Primavera para testes de unidade. Temos um pequeno problema, porém: as cargas código da aplicação de um contexto de aplicação da Primavera a partir de uma lista de locais (arquivos XML) no classpath. Mas quando corremos nossos testes de unidade, queremos que alguns dos grãos de primavera para ser simulações em vez de classes de implementação de pleno direito. Além disso, para alguns testes de unidade que queremos alguns grãos para tornar-se simulações, enquanto que para outros testes de unidade que queremos outros feijões para tornar-se zomba, pois estamos testando diferentes camadas da aplicação.

Tudo isso significa que eu quero redefinir feijão específicas do contexto de aplicação e atualizar o contexto quando desejado. Enquanto isso, eu quero redefinir apenas uma pequena parcela dos grãos localizados em um (ou vários) arquivo de definição de feijão XML original. Não consigo encontrar uma maneira fácil de fazê-lo. É sempre considerado que a Primavera é uma unidade testar framework amigável então eu devo estar faltando alguma coisa aqui.

Você tem alguma idéia de como fazê-lo?

Graças.

Foi útil?

Solução

Gostaria de propor um TestClass costume e algumas regras fáceis para os locais de primavera bean.xml

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    "classpath*:spring/*.xml",
    "classpath*:spring/persistence/*.xml",
    "classpath*:spring/mock/*.xml"})
@Transactional
@TestExecutionListeners({
    DependencyInjectionTestExecutionListener.class,
    TransactionalTestExecutionListener.class,
    DirtiesContextTestExecutionListener.class})
public abstract class AbstractHibernateTests implements ApplicationContextAware 
{

    /**
     * Logger for Subclasses.
     */
    protected final Logger LOG = LoggerFactory.getLogger(getClass());

    /**
     * The {@link ApplicationContext} that was injected into this test instance
     * via {@link #setApplicationContext(ApplicationContext)}.
     */
    protected ApplicationContext applicationContext;

    /**
     * Set the {@link ApplicationContext} to be used by this test instance,
     * provided via {@link ApplicationContextAware} semantics.
     */
    @Override
    public final void setApplicationContext(
            final ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
}

se houver mock-bean.xml no local especificado, eles vão substituir todos bean.xml "real" nos locais "normais" - as suas localizações normais podem diferir

Mas ... eu nunca misturar feijão simulados e não simulados é difícil rastrear problemas, quando a aplicação cresce.

Outras dicas

Uma das razões mola é descrita como teste-friendly é porque pode ser fácil simplesmente new ou coisas simulada no teste de unidade.

Como alternativa usamos a seguinte configuração com grande sucesso, e eu acho que é bastante próximo ao que você quer, eu fortemente recomendá-lo:

Para todos os grãos que precisam de implementações diferentes em contextos diferentes, mude para fiação base de anotação. Você pode deixar os outros como está.

Implementar o seguinte conjunto de anotações

 <context:component-scan base-package="com.foobar">
     <context:include-filter type="annotation" expression="com.foobar.annotations.StubRepository"/>
     <context:include-filter type="annotation" expression="com.foobar.annotations.TestScopedComponent"/>
     <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
 </context:component-scan>

Então você anotar seus vivo implementações com @Repository, o seu rascunho implementações com @StubRepository, qualquer código que deve estar presente no dispositivo de teste unidade apenas com @TestScopedComponent . Você pode se deparar com a necessidade de um par mais anotações, mas estes são um grande começo.

Se você tem um monte de spring.xml, provavelmente você vai precisar fazer alguns novos arquivos Spring XML que, basicamente, contêm apenas as definições de componentes-scan. Você normalmente basta adicionar esses arquivos à sua lista @ContextConfiguration regular. A razão para isso é porque você costuma acabar com configurações diferentes do contexto-scans (confie em mim, você irá fazer mais pelo menos 1 anotações Se você estiver fazendo web-testes, o que contribui para 4 combinações relevantes)

Em seguida, você basicamente usar o

@ContextConfiguration(locations = { "classpath:/path/to/root-config.xml" })
@RunWith(SpringJUnit4ClassRunner.class)

Note que esta configuração faz não permitem que você tenha combinações alternadas de dados stub / ao vivo. Nós tentamos isso, e acho que isso resultou em uma confusão Eu não recomendo ninguém;) Nós ou fio inn o conjunto completo de stubs ou o conjunto completo de serviços ao vivo

.

Nós usamos principalmente dependências stub auto-wired ao testar perto de material gui onde as dependências são geralmente bastante substancial. Em áreas mais limpas do código que usamos teste de unidade mais regular.

Em nosso sistema, temos os seguintes arquivos XML para o componente-scan:

  • para a produção de web comum
  • para iniciar web com topos única
  • para testes de integração (em junit)
  • para testes de unidade (em junit)
  • para testes web selênio (em junit)

Isso significa que temos totalmente 5 configurações de todo o sistema diferentes que podemos iniciar o aplicativo com. Desde nós só usar anotações, a primavera é rápido o suficiente para autowire mesmo aqueles testes de unidade que queremos com fio. Eu sei que isso é pouco tradicional, mas é realmente grande.

testes de integração para fora executado com a configuração completa ao vivo, e uma ou duas vezes eu decidi entrar realmente pragmática e quer ter um 5 fiações ao vivo e uma única simulação:

public class HybridTest {
   @Autowired
   MyTestSubject myTestSubject;


   @Test
   public void testWith5LiveServicesAndOneMock(){
     MyServiceLive service = myTestSubject.getMyService();
     try {
          MyService mock = EasyMock.create(...)
          myTestSubject.setMyService( mock);

           .. do funky test  with lots of live but one mock object

     } finally {
          myTestSubject.setMyService( service);
     }


   }
}

Eu sei que os puristas teste vai ser em cima de mim para isso. Mas às vezes é apenas uma solução muito pragmática que acaba por ser muito elegante quando a alternativa seria realmente muito feio. Novamente é normalmente nessas áreas gui-próximo.

Veja este tutorial com @InjectedMock anotação

Ele me salvou um monte de tempo. Você acabou de usar

@Mock
SomeClass mockedSomeClass

@InjectMock
ClassUsingSomeClass service

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
}

e todos os seus problemas são resolvidos. Mockito irá substituir a injeção primavera dependência com um mock. Eu apenas usei-me e ele funciona muito bem.

Existem algumas soluções muito complicado e poderosos aqui.

Mas há um FAR, muito mais simples maneira de realizar o que Stas pediu, que não envolve a modificação de qualquer coisa diferente de uma linha de código no método de ensaio. Ele trabalha para testes unitários e testes de integração Primavera iguais, para as dependências autowired, campos privados e protegidos.

Aqui está:

junitx.util.PrivateAccessor.setField(testSubject, "fieldName", mockObject);

Você também pode escrever seus testes de unidade não necessita de quaisquer pesquisas em tudo:

@ContextConfiguration(locations = { "classpath:/path/to/test-config.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
public class MyBeanTest {

    @Autowired
    private MyBean myBean; // the component under test

    @Test
    public void testMyBean() {
        ...
    }
}

Isto dá uma maneira fácil de misturar e combinar arquivos de configuração reais com arquivos de teste de configuração.

Por exemplo, quando usando hibernate, eu poderia ter o meu feijão sessionFactory em um arquivo de configuração (para ser usado em ambos os testes e o aplicativo principal), e tem por dataSource feijão em outro arquivo de configuração (pode-se usar um DriverManagerDataSource para um db na memória, o outro pode usar um JNDI-lookup).

Mas, definitivamente dar atenção a @ cletus é advertência; -)

Easy. Você usa um contexto de aplicativo personalizado para os testes de unidade. Ou você não usar um em tudo e você manualmente criar e injetar seus feijões.

Parece-me que seu teste pode ser um pouco demasiado ampla. O teste de unidade é de cerca de teste, bem, unidades. Uma mola de feijão é um exemplo muito bom de uma unidade. Você não deve precisar de todo um contexto de aplicação para isso. Acho que se o seu teste de unidade é tão alto nível que você precisa de centenas de feijão, conexões de banco de dados, etc, então você tem um teste de unidade muito frágil, que vai quebrar no muito próxima mudança, vai ser difícil de manter e realmente isn' t adicionar um monte de valor.

Eu não tenho os pontos de reputação para pilha sobre a resposta de duffymo, mas eu só queria carrilhão e dizer a sua era a resposta "certa" para mim.

instanciar um FileSystemXmlApplicationContext na configuração do seu teste de unidade com um applicationContext.xml personalizado. Nesse xml costume, no topo, faça uma como duffymo indica. Em seguida, declarar o seu feijão simulados, fontes de dados não-JNDI, etc, que irá substituir o id do declarado na importação.

Trabalhou como um sonho para mim.

Talvez você poderia usar eliminatórias para o seu feijão? Você iria redefinir o feijão que você quer zombar-se em um contexto de aplicativo separado e rotulá-los com um "teste" qualificador. Em seus testes de unidade, ao ligar seus feijões sempre especificar o "teste" de qualificação para usar as maquetes.

Eu quero fazer a mesma coisa, e nós estamos encontrando essencial.

O uso atual mecanismo que é bastante manual, mas ele funciona.

Digamos, por exemplo, você deseja zombar de feijão do tipo Y. O que fazemos é cada grão que tem essa dependência fazemos implementar uma interface - "IHasY". Esta interface é

interface IHasY {
   public void setY(Y y);
}

Então, em nosso teste nós chamamos o util método ...

 public static void insertMock(Y y) {
        Map invokers = BeanFactory.getInstance().getFactory("core").getBeansOfType(IHasY.class);
        for (Iterator iterator = invokers.values().iterator(); iterator.hasNext();) {
            IHasY invoker = (IHasY) iterator.next();
            invoker.setY(y);
        }
    }

Eu não quero criar um arquivo xml inteiro só para injetar essa nova dependência e é por isso que eu gosto disso.

Se você está disposto a criar um arquivo XML de configuração, em seguida, o caminho a percorrer seria a criação de uma nova fábrica com o feijão simulados e fazer o seu padrão de fábrica um pai desta fábrica. Certifique-se então que você carregar todos os seus grãos a partir da nova fábrica de criança. Ao fazer isso, o sub-fábrica irá substituir o feijão na fábrica pai quando do id feijão são os mesmos.

Agora, se, no meu teste, Se eu pudesse programação criar uma fábrica, que seria fantástico. Ter que usar xml é muito complicado. Eu estou olhando para criar aquela fábrica criança com código. Em seguida, cada teste pode configurar sua fábrica do jeito que quer. Não há nenhuma razão para que uma fábrica como essa não vai funcionar.

primavera-reinjetar é projetado para grãos substitutos com simulações.

Uma vez que o OP isso veio junto: Springockito

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top