繁体   English   中英

内存数据库配置(HSQLDB),用于Spring启动应用程序中的集成测试

[英]In-memory database configuration (HSQLDB) for integration testing in spring boot app

我开发了一个系统,其基础设施层是在Spring启动(Security,Data JPA,MVC ......)上开发的。 在运行时,系统连接到MySQL,其设置在src/main/resources/application.properties以及.sql中,其中包含一些用户插入和用于身份验证的角色。
对于集成测试,我决定使用HSQLDB隔离数据并执行“安全”测试。 为此,我创建了AbstractIntegrationTest类,其中包含用于创建和清理要从控制器进行测试的表和方法的方法。 所有测试类都扩展它:(我隐藏了不涉及数据库的方法)

@WebAppConfiguration
@ContextConfiguration(classes={LibraryManagerContextConfiguration.class, WebSecurityConfig.class})
public class AbstractIntegrationTest {

    @Autowired
    private WebApplicationContext webApplicationContext;

    @Autowired
    private JwtAuthenticationFilter jwtAuthenticationFilter;

    @Autowired
    private LoginFilter loginFilter;

    private MockMvc mockMvc;

    private static IDatabaseConnection databaseConnection;
    private static Connection connection;
    private static boolean isAfterFirstRun;
    private static Logger logger = LogManager.getLogger(AbstractIntegrationTest.class);

    @BeforeClass
    public static void createDatabase() throws Exception {
        try {
            final Properties properties = loadProperties();

            final String driver = properties.getProperty("datasource.driver");
            final String url = properties.getProperty("datasource.url");
            final String userName = properties.getProperty("datasource.username");
            final String password = properties.getProperty("datasource.password");
            final String schema = properties.getProperty("datasource.schema");

            Class.forName(driver);
            connection = DriverManager.getConnection(url, userName, password);
            databaseConnection = new HsqldbConnection(connection, schema);

        } catch (final SQLException exception) {
            throw new RuntimeException(exception.getMessage(), exception);
        } catch (final ClassNotFoundException exception) {
            throw new RuntimeException(exception.getMessage(), exception);
        }
    }

    @Before
    public void setDatabaseUp() throws Exception {
        if (!isAfterFirstRun) {
            runSQLCommands(getDataSetupFile());
        }
        runSQLCommands(getClearDatabaseFile());
        runSQLCommands(getResetSequencesFile());
        runSQLCommands(getDataFile());
        isAfterFirstRun = true;
    }

    @AfterClass
    public static void closeConnection() throws Exception {
        connection.close();
        databaseConnection.close();
    }

    protected void runSQLCommands(final String file) throws Exception {
        if (file != null) {
            final InputStream stream = getSQLInputStream(file);
            final BufferedReader databaseReader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));

            int i = 1;
            String sqlStatement = null;
            while ((sqlStatement = databaseReader.readLine()) != null) {
                if (sqlStatement.startsWith("--")) {
                    i++;
                    continue;
                }
                final int index = sqlStatement.lastIndexOf(";");
                if (index > -1) {
                    sqlStatement = sqlStatement.substring(0, index + 1);
                }
                if (sqlStatement.trim().length() != 0) {
                    try {
                        connection.createStatement().execute(sqlStatement);
                        logger.info(sqlStatement);
                    } catch (final Exception exception) {
                        logger.error("Error running command on line " + i + " of file " + file + ": " + exception.getMessage());
                        throw new RuntimeException(exception);
                    }
                }
                i++;
            }
        }
    }

    protected IDatabaseConnection getConnection() {
        return databaseConnection;
    }

    protected static IDataSet getDataSet(final String dataset) {
        try {
            final InputSource source = new InputSource(AbstractIntegrationTest.class.getResourceAsStream(dataset));
            return new FlatXmlDataSetBuilder().build(source);
        } catch (final Exception exception) {
            throw new RuntimeException("Cannot read the dataset file " + dataset + "!", exception);
        }
    }

    private static Properties loadProperties() throws Exception {
        final InputStream stream = ClassLoader.getSystemResourceAsStream("datasource.properties");
        if (stream == null) {
            throw new FileNotFoundException("File erm.properties not found. A file named erm.properties must be present "
                    + "in the src/test/resources folder of the project whose class is being tested.");
        }
        final Properties properties = new Properties();
        properties.load(stream);
        return properties;
    }

    private static InputStream getSQLInputStream(final String fileName) {
        return AbstractIntegrationTest.class.getResourceAsStream(fileName);
    }

    protected String getClearDatabaseFile() {
        return "/database/clear-database.sql";
    }

    protected String getDataSetupFile() {
        return "/database/database-setup.sql";
    }

    protected String getDataFile() {
        return "/database/data.sql";
    }

    protected String getResetSequencesFile() {
        return "/database/reset-sequences.sql";
    }

}

LibraryManagerContextConfigurationWebSecurityConfig类包含域和基础结构bean声明,因此它们构成了spring上下文。

该类位于src/test/javadatasource.properties文件与测试.sql一起位于src/test/resources 测试类运行完美,测试脚本运行,表创建,但是当测试库在测试期间查找某些数据时,它会搜索MySQL而不是HSQLDB。 这是一个测试类:

@RunWith(SpringJUnit4ClassRunner.class)
public class AuthenticationIntegrationTest extends AbstractIntegrationTest {

    @Test
    public void shouldGetAuthorizationJwt() throws Exception {

        final String jsonCredentials = "{"
                    + "\"username\" : \"augusto\","
                    + "\"password\" : \"spring\""
                + "}";

        final MvcResult result =  performRESTLogin(jsonCredentials);
        final MockHttpServletResponse response = result.getResponse();
        final int status = response.getStatus();
        final String jwt = response.getHeader("Authorization");

        assertThat(status, is(200));
        assertThat(jwt, notNullValue());
    }

}

当我使用仅存在于测试数据库中的用户名和密码并获得403状态而MySQL值达到200状态时,我验证了这一点。 看来,在编写HSQLDB之后,将读取main的.properties和.sql并覆盖正在使用的数据库的设置。

application.properties:

server.contextPath=/librarymanager
server.port: 8081

spring.datasource.url = jdbc:mysql://localhost:3306/librarymanager
spring.datasource.username = root
spring.datasource.password = root
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = create-drop
spring.jpa.hibernate.naming.strategy = org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

datasource.properties:

datasource.class=org.hsqldb.jdbc.JDBCDataSource
datasource.driver=org.hsqldb.jdbc.JDBCDriver
datasource.url=jdbc:hsqldb:mem:librarymanager;sql.syntax_ora=true
datasource.schema=sa
datasource.username=sa
datasource.password=

pom.xml中的DB依赖项:

<!-- Banco de dados -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <scope>test</scope>
        </dependency>

执行成功的缺失是什么? 使用注释? 为dev和测试创建.properties与spring.profiles.active = dev/test conf分开,使用spring.profiles.active = dev/test创建主.properties以在配置文件之间切换? 我想要一些建议。

谢谢。

github中的项目链接: https//github.com/augustodossantosti/librarymanager-jwtauth

谢谢你的建议。 实际上使用框架是最好的选择。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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