2009-11-10 15 views
1

J'ai demandé un question, dont le titre aurait pu être trompeur, donc je vais essayer de poser à nouveau la question avec beaucoup de détails. (Je sais que la question semble longue mais s'il vous plaît ours avec moi)comment tester l'intégration d'un DAO construit avec spring + iBatis

Ce que j'essaie de faire: Je veux simplement écrire un cas de test pour mon DAO et le faire fonctionner. Je sais que mon DAO fonctionne bien à l'intérieur du conteneur (serveur d'applications) mais lorsque j'appelle DAO à partir du cas de test ... cela ne fonctionne pas. Je pense parce que c'est à l'extérieur du conteneur.

Stuff dans mon ressort pour-iBatis.xml

<bean id="IbatisDataSourceOracle" class="org.springframework.jndi.JndiObjectFactoryBean"> 
    <property name="jndiName" value="jdbc/RSRC/my/db/oltp"/> 
</bean> 
<bean id="MapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> 
    <property name="configLocation" value="classpath:sql-map-config-oracle.xml"/> 
    <property name="dataSource" ref="IbatisDataSourceOracle"/> 
</bean> 

Stuff dans mon sql-map-config-oracle.xml

<sqlMapConfig> 
    <settings enhancementEnabled="true" useStatementNamespaces="true" /> 
<transactionManager type="JDBC"> 
    <dataSource type="JNDI"> 
    <property name="DataSource" value="jdbc/RSRC/my/db/oltp"/> 
    </dataSource> 
</transactionManager> 
     <sqlMap resource="mymapping.xml"/> 
</sqlMapConfig> 

ma classe abstraite:

public abstract MyAbstract { 
    public SqlMapClientTemplate getSqlTempl() SQLException{ 
     public static final String ORCL = "jdbc/RSRC/PIH/eiv/oltp"; 
     try { 
      ApplicationInitializer.getApplicationContext().getBean("MapClient"); 
      SqlMapClient scl = (SqlMapClient) ApplicationInitializer.getApplicationContext().getBean("MapClient"); 
      DataSource dsc = (DataSource) MyServiceLocator.getInstance().getDataSource(ORCL); 
      return new SqlMapClientTemplate (dsc, scl); 
     } 
     catch (NamingException e) 
     { 
      log.error(ne.getMessage(), e); 
      throw new SQLException("some error here: " + e.getMessage()); 
     } 
    } 
} 

mon DAO:

public class MyDAO extends MyAbstract{ 
public AnObject getSomething(String id) 
     { 
     HashMap myMap = new HashMap(); 
     myMap.put("id", id); 
     try { 
      setSqlMapClientTemplate(getSqlTempl()); 
     } 
     catch (SQLException ne) 
     { 
      log.error (ne.getMessage(), ne); 
     } 
     getSqlMapClientTemplate().queryForList("mymapping.someproc", myMap); 
     return AnObject ((List)myMap.get("firstresult").get(0)); 
     } 
} 

Mytests

public class MyDAOTests extends TestCase { 

public void testMyDAO() 
{ 
    MyDAO myd = new MyDAO(); 
    AnObject ano = myd.getSomething("15"); 
    assertEquals("1500", ano.getContentId()); 

} 
} 

J'ai essayé de présenter le problème dans cet extrait de code. Le test échoue car il n'est pas en mesure d'obtenir la connexion à la base de données ... car il est en dehors du conteneur. Je sais que la conception peut être corrigée pour faire un meilleur usage des injections de dépendance. Pouvez-vous me montrer, à partir de cet extrait, quelles améliorations pourraient être apportées pour que les tests puissent fonctionner?

J'ai eu du mal avec cela et j'apprécierais vraiment de l'aide. PS: J'ai dû faire usage de setSqlMapClientTemplate() parce que je veux appeler à mon DAO pour être simplement simple MyDAO myd = new MyDAO() Je ne veux pas faire l'interface pour chacun de mon DAO.

+2

Pourquoi votre classe abstraite a-t-elle le nom JNDI câblé dans votre classe abstraite? Juste l'injecter en utilisant le printemps. – duffymo

+0

Cela ressemble à une application écrite pour le printemps par quelqu'un qui ne comprend pas réellement Spring. Je me sens mal pour toi. –

+0

Je me sens mal pour moi-même ... pour ne pas connaître le printemps assez bien pour corriger moi-même ce code. la faute est à moi ... – Drake

Répondre

6

Il y a beaucoup de problèmes ici. D'abord, je compte trois citations de la chaîne de recherche JNDI dans votre petit exemple. DRY vous dirait de l'écrire une fois et de s'y référer, si possible. Deuxièmement, je n'apprécie pas beaucoup votre DAO. Est-ce vraiment ce que vous écrivez, ou est-ce juste un exemple? Je ne pense pas que ce soit l'idiome du printemps. Il n'y a pas d'interface. Comment allez-vous faire des transactions déclaratives sans un? Je recommande de regarder le Spring docs for iBatis plus attentivement. Troisièmement, je recommanderais d'utiliser JUnit 4.4 ou, mieux encore, les annotations de TestNG idiom. Consultez également Spring @ContextConfiguration pour injecter les beans dont vous avez besoin dans setUp. En quatrième lieu, vos DAO ne peuvent pas fonctionner car vous avez besoin d'un service de recherche JNDI en cours d'exécution et vous ne pouvez pas en obtenir un sans le conteneur. La réponse est d'avoir une source de données DriverManager pour vos tests.

MISE À JOUR: Voici une idée à essayer: Utilisez le Spring idiom for iBatis. Si l'héritage vous empêche de le faire, peut-être que le printemps n'est pas votre réponse. Une fois que vous faites cela, tout ce que vous avez à faire est de remplacer le contexte de l'application de la source de données pour utiliser DriverManager au lieu de JNDI pour votre test.

+0

** Premier **: comprendre c'est mauvais mais quel est 1 endroit je devrais le garder? vous avez dit injecter utilise le printemps. Qu'est-ce que cela veut dire exactement? Des trois citations, est-ce que j'utilise l'injection de ressort quelque part? comment ferais-je ça? ** Deuxième **: Je change le code existant. il y a beaucoup de code qui appelle les méthodes DAO. Si je suis exactement l'idiome du printemps, je devrais revenir en arrière et changer la façon dont les DAO sont appelés. ** Quatrième **: au lieu de MyServiceLocator je peux utiliser la source de données DriverManager mais qu'en est-il de .getBean ("MapClient") ;? comment vais-je obtenir cela sans le conteneur? et merci beaucoup – Drake

+0

"Je change de code hérité" - alors peut-être que le printemps n'est pas la réponse à votre situation. Quel problème essayez-vous de résoudre? – duffymo

+0

Dans le code existant, je convertis le code JDBC en iBatis. Si je retire le nom JNDI de ma classe abstraite, je n'utiliserai pas MyServiceLocator. Mais alors, comment puis-je obtenir la DataSource dans la classe MyAbstract? J'ai lu le chapitre 11 du printemps mais ils ne montrent pas comment obtenir le nom JNDI comme un bean et ont une source de données .. – Drake