简体   繁体   中英

Are there any in-memory / mocked MySQL packages for unit testing in Spring?

In the past I've used Fongo to write unit/integration tests around Mongo calls, and it's really nice. Fongo stores all the data in-memory, without a database, which is exactly what you would want for a unit test.

I'm wondering if there are any packages out that to provide the same concept for emulating MySQL? I'm using Spring and the JdbcTemplate class to do my querying; what I'm hoping for is something I can drop in and any calls to the JdbcTemplate will essentially be emulated.

Do any such packages exist? Or are there other techniques to accomplish this?

We use HyperSQL's ability to run in-memory for this purpose. It isn't 100% compatible with MySQL, but it works for most purposes.

This connection string tells HyperSQL to use an in-memory database. See the doc for more details.

A mem: database is specified by the mem: protocol. For mem: databases, the path is simply a name. Several mem: databases can exist at the same time and distinguished by their names. In the example below, the database is called "mymemdb":

Connection c = DriverManager.getConnection("jdbc:hsqldb:mem:mymemdb", "SA", "");

Then when you set up your JDBCTemplate you can just use a different testing version of the spring xml file.

If you are using Spring 4 its really easy. Here is some example code from a DAO test. Its specific for myBatis. I also use the HSQLDB in memory database for unit-testing DAOs.

@RunWith(SpringJUnit4ClassRunner.class)
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional
@ContextConfiguration("classpath:testApplicationContext.xml")
@SqlGroup({
  @Sql(scripts = "/com/acme/restangle/dao/test-person-data.sql",
  executionPhase = BEFORE_TEST_METHOD),
  @Sql(
    scripts = "/com/acme/restangle/dao/reset-person-data.sql",
    executionPhase = AFTER_TEST_METHOD)
})
public class PersonDaoImplTest
{
  @Autowired
  private PersonDao dao;

  @Autowired
  private SqlSessionTemplate sqlSessionTemplate;

  @Autowired
  private JdbcTemplate jdbcTemplate;

  @Before
  public void setUp() throws Exception
  {
    sqlSessionTemplate.getConfiguration().setCacheEnabled(false);
    sqlSessionTemplate.getConfiguration().setLocalCacheScope(LocalCacheScope.STATEMENT);
    assertFalse("expected myBatis cache to be disabled", sqlSessionTemplate.getConfiguration().isCacheEnabled());
  }

  @Test
  public void testInsert() throws Exception
  {
    assertEquals(1, JdbcTestUtils.countRowsInTable(jdbcTemplate, "PERSON"));

    assertNull(dao.insert(null));

    Person person = new Person();
    person.setFirstName("firstName");
    person.setMiddleName("middleName");
    person.setLastName("lastName");
    person.setGender(Gender.MALE);
    person.setEthnicity(Ethnicity.ASIAN);

    Person insertedPerson = dao.insert(person);
    assertNotNull(insertedPerson);
    assertEquals(2, insertedPerson.getId());
    assertEquals(person.getFirstName(), insertedPerson.getFirstName());
    assertEquals(person.getMiddleName(), insertedPerson.getMiddleName());
    assertEquals(person.getLastName(), insertedPerson.getLastName());
    assertEquals(person.getGender(), insertedPerson.getGender());
    assertEquals(person.getEthnicity(), insertedPerson.getEthnicity());
    assertEquals(person.isDeceased(), insertedPerson.isDeceased());
  }

This will load your schema (create the tables etc) and insert fresh data. You can also add annotations on each test method if need to. Here I needed the same data for all tests. It will rollback everything for each test.

If you use auto-increments you'll need to reset them:

delete from PERSON;
ALTER TABLE PERSON ALTER COLUMN ID RESTART WITH 1;

Here is a sample test context for Spring. In there you can see how the schema DDL is loaded:

  <context:annotation-config/>
  <context:component-scan base-package="com.acme.restangle" />

  <jdbc:embedded-database id="dataSource">
    <jdbc:script location="classpath:restangle-schema.sql"/>
  </jdbc:embedded-database>

  <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation" value="classpath:SqlMapConfig.xml"/>
  </bean>

  <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate" primary="true">
    <constructor-arg index="0" ref="sqlSessionFactory" />
  </bean>

  <!-- scan for mappers and let them be autowired -->
  <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.acme.restangle.persistence" />
  </bean>

  <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"/>
  </bean>

  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
  </bean>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM