2009-11-10 4 views
1

Я спросил question, название которого могло бы ввести в заблуждение, поэтому я попытаюсь снова задать вопрос с подробным описанием. (я знаю, вопрос кажется длинным, но, пожалуйста, несите меня)Как интегрировать тест DAO, построенный с пружиной + iBatis

Что я пытаюсь сделать: Я просто хочу написать тестовый пример для моего DAO и заставить его работать. Я знаю, что моя DAO работает нормально внутри контейнера (сервер приложений), но при вызове DAO из тестового примера ... это не работает. Я думаю, потому что его вне контейнера.

Материал в моей весна-за-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> 

Материала в моей SQL-карте-конфиг-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> 

мой абстрактный класс:

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

мой 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()); 

} 
} 

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

Я боролся с этим и очень ценю некоторую помощь.

PS: Мне нужно было использовать setSqlMapClientTemplate(), потому что я хочу, чтобы звонок в мой DAO был просто простым. MyDAO myd = new MyDAO() Я не хочу создавать интерфейс для каждого из моих DAO.

+2

Почему в вашем абстрактном классе есть имя JNDI, жестко подключенное к нему? Просто добавьте его с помощью Spring. – duffymo

+0

Это похоже на приложение, написанное для Spring кем-то, кто на самом деле не понимал Весну. Мне тебя жаль. –

+0

Мне плохо для себя ... для того, чтобы не знать весну достаточно хорошо, чтобы исправить этот код сам. ошибка моя ... – Drake

ответ

6

Здесь много проблем.

Во-первых, я считаю три цитаты строки поиска JNDI в вашем маленьком примере. DRY сказал бы вам написать его один раз и обратиться к нему, если это возможно.

Во-вторых, я не очень ценю ваш DAO. Это действительно то, что вы пишете, или это просто пример? Я не думаю, что это весенняя идиома. Нет интерфейса. Как вы будете делать декларативные транзакции без них? Я бы рекомендовал внимательно посмотреть на Spring docs for iBatis.

В-третьих, я бы рекомендовал использовать JUnit 4.4 или, еще лучше, тег TestNG - аннотации. Также проверьте Spring @ContextConfiguration, чтобы ввести нужные вам компоненты в setUp.

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

ОБНОВЛЕНИЕ: Попробуйте использовать: Spring idiom for iBatis. Если наследие мешает вам это сделать, возможно, Spring не является вашим ответом.

Как только вы сделаете это, все, что вам нужно сделать, это переопределить контекст приложения источника данных, чтобы использовать DriverManager вместо JNDI для вашего теста.

+0

** Первый **: понять, что это плохо, но что такое 1 место, которое я должен сохранить? вы сказали, что инъекция использует весну. Что именно это значит? Из трех цитат я где-то использую пружинную инъекцию? как бы я это сделал? ** Второе **: Я меняю устаревший код. существует много кода, вызывающего методы DAO. Если я буду следовать весенней идиоме точно, тогда мне придется вернуться и изменить способ, которым звонят DAO. ** Четвертый **: вместо MyServiceLocator я могу использовать источник данных DriverManager, но как насчет .getBean («MapClient») ;? как я получу это без контейнера? и спасибо большое – Drake

+0

«Я меняю устаревший код» - тогда, возможно, Spring не является ответом на вашу ситуацию. Какую проблему ты пытаешься решить? – duffymo

+0

В устаревшем коде я конвертирую код JDBC в iBatis. Если я выберу имя JNDI из моего абстрактного класса, то я не буду использовать MyServiceLocator. Но как я могу получить DataSource в классе MyAbstract? Я читаю главу 11 весны, но они не показывают, как получить имя JNDI как bean-компонент и иметь источник данных из него. – Drake