2017-04-11 79 views
1

我開發了一個系統,其基礎架構層是在Spring引導(安全性,數據JPA,MVC ...)上開發的。在運行時,系統連接到MySQL,其設置位於src/main/resources/application.properties以及包含一些用戶插入和角色以進行身份​​驗證的.sql。
對於集成測試,我決定使用HSQLDB來隔離數據並執行「安全」測試。爲此我創建了類AbstractIntegrationTest,其中包含創建和清理要從控制器進行測試的表和方法的方法。所有測試類擴展它:(我不涉及數據庫的隱藏方法)用於在彈簧啓動應用程序中進行集成測試的內存數據庫配置(HSQLDB)

@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類包含的領域和基礎設施豆類聲明,以他們做了Spring上下文。

本課程是在src/test/javadatasource.properties文件以及測試.sql在src/test/resources。測試類運行良好,運行測試腳本,創建表,但是當Repository在測試期間查找某些數據時,它將搜索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= 

DB依賴在pom.xml中:

<!-- 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,並使用BDs conf和主要.properties與spring.profiles.active = dev/test在配置文件之間切換?我想提出一些建議。

感謝。在github上

項目鏈接:https://github.com/augustodossantosti/librarymanager-jwtauth

+1

我認爲它更好地使用不同的屬性爲不同的環境,以避免這種混淆。 application-test.properties,application-prod.properties – CrazyMac

+0

您正在使它變得複雜...只需提供一個單獨的屬性文件進行測試,其中包含hsqldb的信息,加載該文件以覆蓋其他屬性...使用框架不反對它。此外,您不應該爲每個測試重新創建數據庫,進行測試'@ Transactional',並在測試完成後將所有內容回滾。節省您很多時間。 –

+0

感謝您的建議。實際上,使用框架是最好的選擇。 –

回答

0

感謝您的建議。實際上,使用框架是最好的選擇。

相關問題