2

我有一个围绕特定服务定义的日志记录方面。我正在使用 Spring AOP 并建议使用一些服务方法来记录与这些方法调用相关的特定应用程序事件。

例如,我使用 @AfterThrowing 注释来检测方法调用中的失败,以便我可以相应地记录。我的服务方法被标记为@Transactional。

正如您可能知道的那样,在提交事务后调用日志记录方面逻辑非常重要,否则我的日志记录方面将错过与提交失败的事务相关的任何错误。更糟糕的是,任何与成功的方法调用相关的日志消息都将被写入,即使该方法在事务提交后实际上失败了。

通过确保我正确定义了方面顺序优先级,我可以完美地工作。我最大的问题是我希望能够编写一个测试(集成测试似乎是唯一的选择),它将断然确认订单优先级得到尊重。鉴于顺序优先级是一种配置,很容易预见将来会有人出现并调整配置而没有意识到他们正在破坏关键代码。

所以,我的理论是我需要编写一个测试,故意导致事务在提交时失败,然后检查我的日志记录中的逻辑 @AfterThrowing 切入点是否在之后被调用。

以前有人遇到过这种需求吗?我确信这是使用 AOP 时的常见场景。

4

2 回答 2

1

如果您编写一个上下文感知的测试,您可以从上下文中获取所有方面并断言该顺序是预期的。

另一种解决方案是找到任何可能引发重复键异常的资源,然后使用相同的值调用它两次。至少第二次调用应该记录异常。

于 2011-11-11T20:03:40.877 回答
1

您可能希望为测试加载整个 Spring 上下文,但 DataSource除外。对于数据库的东西,看看MockRunner。它有一组很好的模拟 JDBC 类。

在您的 Spring 上下文中(可能通过单独的 xml 文件),将您的真实 DataSource 替换为 aMockDataSource以进行测试。从测试用例的上下文中检索此 DataSource,您可以执行以下操作:

MockResultSet rs = new MockResultSet("SELECT 1");
rs.addRow(new Object[] { 1 });

MockConnection con = new MockConnection();
con.getPreparedStatementResultSetHandler().prepareResultSet("SELECT 1", rs);

PreparedStatement ps = connection.prepareStatement("SELECT 1");
ps.executeQuery()

请注意,如果您想抛出异常,结果集处理程序 (via AbstractResultSetHandler) 有一个prepareThrowsSQLException()可用于指定特定 SQL 字符串应抛出异常的方法。

根据您在每个测试用例之前需要设置的内容,将上述方法与@Before和方法混合并匹配。@BeforeClass请注意,Mock JDBC 语句会记录所有已执行的 SQL,因此如果您正在运行大量 JDBC 调用(数百万?),内存/性能可能会成为问题。为每个测试用例创建一个新的连接/语句可能是最简单的。

最后,如果您使用 Maven,MockRunner 会引入许多其他 JDBC 模拟不需要的东西。这是我在 pom.xml 中定义它的方式:

<dependency>
    <groupId>com.mockrunner</groupId>
    <artifactId>mockrunner-jdk1.5-j2ee1.3</artifactId>
    <version>0.4</version>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>xml-apis</groupId>
            <artifactId>xml-apis</artifactId>
        </exclusion>
        <exclusion>
            <groupId>cglib-nodep</groupId>
            <artifactId>cglib-nodep</artifactId>
        </exclusion>
        <exclusion>
            <groupId>jboss</groupId>
            <artifactId>jboss-jee</artifactId>
        </exclusion>
        <exclusion>
            <groupId>struts</groupId>
            <artifactId>struts</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.mockejb</groupId>
            <artifactId>mockejb</artifactId>
        </exclusion>
        <exclusion>
            <groupId>nekohtml</groupId>
            <artifactId>nekohtml</artifactId>
        </exclusion>
        <exclusion>
            <groupId>commons-validator</groupId>
            <artifactId>commons-validator</artifactId>
        </exclusion>
        <exclusion>
            <groupId>commons-digester</groupId>
            <artifactId>commons-digester</artifactId>
        </exclusion>
        <exclusion>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
        </exclusion>
        <exclusion>
            <groupId>xerces</groupId>
            <artifactId>xercesImpl</artifactId>
        </exclusion>
        <exclusion>
            <groupId>jdom</groupId>
            <artifactId>jdom</artifactId>
        </exclusion>
        <exclusion>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
        </exclusion>
    </exclusions>
</dependency>
于 2011-11-12T03:14:38.657 回答