Question

nous utilisons Spring pour mes fins d'application, et le cadre d'essais de printemps pour les tests unitaires. Nous avons un petit problème cependant: le code d'application charge un contexte d'application Spring à partir d'une liste d'emplacements (fichiers xml) dans le classpath. Mais quand nous exécutons nos tests unitaires, nous voulons quelques-uns des grains de printemps à se moque au lieu des cours de mise en œuvre à part entière. De plus, pour certains tests unitaires, nous voulons des haricots pour devenir raille, alors que pour d'autres tests unitaires, nous voulons que d'autres haricots à devenir raille, comme nous testons différentes couches de l'application.

Tout cela signifie que je veux redéfinir les haricots spécifiques du contexte d'application et actualiser le contexte quand on le souhaite. Tout en faisant cela, je veux redéfinir seulement une petite partie des grains situés dans un (ou plusieurs) fichier de définition des haricots XML d'origine. Je ne peux pas trouver un moyen facile de le faire. Il est toujours considéré que le printemps est une unité test cadre convivial, donc je dois manquer quelque chose.

Avez-vous des idées sur la façon de le faire?

Merci.

Était-ce utile?

La solution

Je propose un TestClass de coutume et quelques règles faciles pour les emplacements des bean.xml de printemps

@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;
    }
}

s'il y a maquette bean.xml à l'emplacement spécifié, ils remplacent toutes bean.xml « réel » dans les endroits « normaux » - vos emplacements normaux peuvent différer

mais ... je ne mélanger les haricots simulacres et non simulacres il est difficile de tracer des problèmes, lorsque l'application grandit.

Autres conseils

L'une des raisons ressort est décrit comme convivial test est car il peut être facile de simplement nouveau ou des trucs faux dans le test unitaire.

Sinon nous avons utilisé la configuration suivante avec un grand succès, et je pense qu'il est assez proche de ce que vous voulez, je fortement recommander:

Pour tous les haricots qui ont besoin d'implémentations différentes dans des contextes différents, passer à câblage en fonction d'annotation. en l'état, vous pouvez laisser les autres.

Mettre en œuvre l'ensemble des annotations

suivant
 <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>

Ensuite, vous annoter vos en direct mises en œuvre avec @Repository, vos stub mises en œuvre avec @StubRepository, tout code qui devrait être présent dans l'appareil de test d'unité UNIQUEMENT avec @TestScopedComponent . Vous pouvez exécuter en besoin d'un couple plus annotations, mais ce sont un bon début.

Si vous avez beaucoup de spring.xml, vous aurez probablement besoin de faire quelques nouveaux fichiers XML de printemps qui contiennent essentiellement que les définitions de balayage des composants. Vous auriez normalement juste ces fichiers ajoutez à votre liste de @ContextConfiguration régulière. La raison en est que vous vous retrouvez souvent avec différentes configurations du contexte scans (croyez-moi, vous faire au moins 1 annotations plus si vous faites des tests web, ce qui rend pour 4 combinaisons pertinentes)

Ensuite, vous utilisez essentiellement le

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

Notez que cette configuration ne pas vous permettent d'avoir des combinaisons alternatives de données stub / live. Nous avons essayé cela, et je pense que a donné lieu à un gâchis que je ne recommanderais à personne;) Nous soit auberge de fil l'ensemble des talons ou l'ensemble complet de services en direct

.

Nous utilisons principalement les dépendances de stub filaire automatiquement lors du test IUG près des choses où les dépendances sont généralement assez importants. Dans les zones plus propres du code que nous utilisons tests unitaires plus réguliers.

Dans notre système, nous avons les fichiers xml-suivants pour le composant-scan:

  • pour la production web régulière
  • pour le démarrage web avec des talons uniquement
  • pour les tests d'intégration (en JUnit)
  • pour les tests unitaires (JUnit en)
  • pour les tests Web de sélénium (en JUnit)

Cela signifie que nous avons totalement 5 configurations différentes à l'échelle du système que nous pouvons démarrer l'application avec. Étant donné que nous utilisons des annotations, le printemps est assez rapide pour lier automatiquement même les tests unitaires que nous voulons câblé. Je sais que c'est untraditional, mais il est vraiment super.

tests d'intégration fonctionnent avec une configuration complète en direct, et une ou deux fois j'ai décidé de faire vraiment pragmatique et que vous voulez avoir un 5 live et un câblages simple maquette:

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);
     }


   }
}

Je sais que les puristes de test vont être sur moi pour cela. Mais parfois, il est juste une solution très pragmatique qui se révèle être très élégant quand l'alternative serait vraiment vraiment moche. Encore une fois il est généralement dans les zones IUG près.

Voir ce tutoriel avec annotation @InjectedMock

Il m'a sauvé beaucoup de temps. Vous utilisez simplement

@Mock
SomeClass mockedSomeClass

@InjectMock
ClassUsingSomeClass service

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

et tous vos problèmes sont résolus. Mockito remplacera l'injection de dépendance à ressort avec une maquette. Je viens d'utiliser moi-même et il fonctionne très bien.

Il existe des solutions très complexes et puissantes énumérées ici.

Mais il y a une FAR, FAR façon plus simple pour accomplir ce que Stas a demandé, qui ne comporte pas de modifier quoi que ce soit d'autre d'une ligne de code dans la méthode d'essai. Il fonctionne pour les tests unitaires et tests d'intégration de printemps aussi bien, les dépendances, les champs autowired privés et protégés.

Ici, il est:

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

Vous pouvez également écrire vos tests unitaires pour ne pas exiger du tout des recherches:

@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() {
        ...
    }
}

Cela donne un moyen facile de mélanger et assortir de vrais fichiers de configuration avec les fichiers de configuration de test.

Par exemple, lors de l'utilisation mise en veille prolongée, je pourrais avoir mon haricot sessionFactory dans un fichier de configuration (à utiliser dans les deux essais et l'application principale), et ont par haricot dataSource dans un autre fichier de configuration (on peut utiliser un DriverManagerDataSource à un, l'autre peut utiliser un JNDI-lookup) db en mémoire.

Mais, certainement prendre garde de son @ de Cletus avertissement; -)

facile. Vous utilisez un contexte d'application personnalisée pour vos tests unitaires. Ou vous n'utilisez pas du tout et vous créez manuellement et injectez vos haricots.

Il me semble que votre test pourrait être un peu trop large. Les tests unitaires sont sur le test, bien, unités. Un grain de printemps est un très bon exemple d'une unité. Vous ne devriez pas avoir besoin d'un contexte d'ensemble de l'application pour cela. Je trouve que si vos tests unitaires est si haut niveau que vous avez besoin des centaines de haricots, les connexions de base de données, etc alors vous avez un test unitaire vraiment fragile qui va se briser sur le changement suivant, sera difficile à maintenir et ISN vraiment » t d'ajouter beaucoup de valeur.

Vous pouvez utiliser la fonction import votre contexte d'application de test pour charger dans les grains de prod et remplacer ceux que vous voulez. Par exemple, ma source de données prod est généralement acquis par JNDI, mais quand je teste-je utiliser une source de données DriverManager donc je n'ai pas démarrer le serveur d'applications pour tester.

Je n'ai pas les points de réputation à poil sur la réponse de duffymo, mais je voulais juste sonner et dire son était la « bonne réponse » pour moi.

instancier un FileSystemXmlApplicationContext dans la configuration de votre test unitaire avec un applicationContext.xml personnalisé. Dans ce xml personnalisé, en haut, comme faire une duffymo indique. Ensuite, déclarer vos haricots simulacres, sources de données non JNDI, etc, qui remplacera les id déclarées dans l'importation.

A travaillé comme un rêve pour moi.

Vous n'avez pas besoin d'utiliser des contextes de test (peu importe est XML ou Java). Depuis le démarrage de printemps 1.4, il est disponible nouvelle annotation @MockBean qui a introduit le support natif pour les moqueries et Espionner des haricots printemps.

Peut-être que vous pourriez utiliser des qualificatifs pour vos haricots? Vous redéfinir les haricots que vous voulez moquer dans un contexte d'application séparée et les étiqueter avec un qualificatif « test ». Dans vos tests unitaires, lors du câblage vos haricots toujours spécifier le qualificatif « test » pour utiliser les maquettes.

Je veux faire la même chose, et nous constatons qu'il est essentiel.

Le mécanisme actuel que nous utilisons est assez manuel, mais cela fonctionne.

Dites par exemple, vous souhaitez se moquer des haricots de type Y. Ce que nous faisons est chaque grain qui a cette dépendance nous faisons mettre en œuvre une interface - « IHasY ». Cette interface est

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

Ensuite, dans notre test, nous appelons la méthode util ...

 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);
        }
    }

Je ne veux pas créer un fichier xml tout juste pour injecter cette nouvelle dépendance et c'est la raison pour laquelle j'aime cela.

Si vous êtes prêt à créer un fichier de configuration XML alors la voie à suivre serait de créer une nouvelle usine avec les haricots simulacres et faites votre usine par défaut un parent de cette usine. Assurez-vous alors que vous chargez tous vos haricots de la nouvelle usine de l'enfant. Lors de cette opération sous-usine supplante les haricots dans l'usine mère lorsque l'ID de Bean sont les mêmes.

Maintenant, si, dans mon test, Si je pouvais programme créer une usine, ce serait génial. Le fait de devoir utiliser xml est trop lourd. Je cherche à créer cette usine d'enfants avec le code. Ensuite, chaque test peut configurer son usine comme il veut. Il n'y a aucune raison pourquoi une usine comme ça ne fonctionnera pas.

ressort réinjection est conçu pour remplacer les fèves avec des objets fantaisie.

Depuis l'OP cela a venir: Springockito

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top