【问题标题】:Using TestWatcher for logging assertion failures in test cases使用 TestWatcher 记录测试用例中的断言失败
【发布时间】:2015-08-12 07:46:10
【问题描述】:

上下文/场景:

我正在使用 JUnit 和 Apache Log4J 来学习 TDD 和日志记录服务的最佳实践。我有一个GenericTaskInterpreter 类,它有一个方法connectToMySQL,它将尝试连接到MySQL 数据库并返回java.sql.Connection 类型的对象。

class GenericTaskInterpreter {

    /**
    * This method will attempt to connect to a MySQL database
    * and return an object of type java.sql.Connection
    */
    public Connection connectToMySQL() {
        Connection connection = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection(
            "jdbc:mysql://localhost:3306/TestDatabase", "root",
            "password");
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
}

我有一个类GenericTaskInterpreterTests,我已经为这个方法(和其他方法)编写了测试用例。

public class GenericTaskInterpreterTests extends TestCase {

    private static final GenericTaskInterpreter genericTaskInterpreter = new GenericTaskInterpreter();

    private static final Logger logger = LogManager.getLogger(GenericTaskInterpreterTests.class);

    private static boolean setUpIsDone = false;

    private static boolean tearDownIsDone = false;

    private static FileAppender fileAppender;

    @Rule
    public TestRule watchman = new TestWatcher() {

        private String watchedLog;

        // Overridden methods apply, succeeded, skipped, starting and finished....

    };

    protected void setUp() throws Exception {
        if (setUpIsDone) {
            return;
        }
        // Do the setup.
        fileAppender = new FileAppender();
        fileAppender.setName("FileLogger");
        fileAppender.setFile("/path/to/log4j-application.log");
        fileAppender.setLayout(new PatternLayout("%d %-5p [%c{1}.%M] %m%n"));
        fileAppender.setThreshold(Level.DEBUG);
        fileAppender.setAppend(true);
        fileAppender.activateOptions();

        LogManager.getRootLogger().addAppender(fileAppender);
        setUpIsDone = true;
        //logger.info("####### All configurations complete... #######");
        logger.info("####### Starting test cases... #######");

    }

    protected void tearDown() throws Exception {

        if (tearDownIsDone) {
            return;
        }
        // Do the teardown.
        //fileAppender.close();
        LogManager.getRootLogger().removeAppender(fileAppender);
        tearDownIsDone = true;   
    }

    public void testconnectToMySQLIfConnectionObjectIsNotNull() {
        assertNotNull(genericTaskInterpreter.connectToMySQL());
    }
}

问题:

  • 如何使用 TestWatcher 在此测试用例场景中记录断言失败?
  • 有没有比使用 TestWatcher 更好的选择?

【问题讨论】:

  • 还有其他选择吗?取决于:您的 TestWatcher 应该如何处理这些信息?
  • 目前写入日志文件。

标签: java unit-testing junit log4j


【解决方案1】:

当任何事件(设置、测试、清理失败/通过/跳过)发生时,您可能希望附加一个通用/离散结果文件。

如果您并行运行测试,则必须将日志写入同步到结果文件

为此,您可能必须从 junit API 覆盖 RunListener 中的方法

http://junit.sourceforge.net/javadoc/org/junit/runner/notification/RunListener.html 属于 RunListener 类

【讨论】:

    【解决方案2】:
    @Rule
    public TestRule watchman = new TestWatcher() {
    
        @Override
        protected void succeeded(final Description description) {
            logger.info(String.format("Success: %s", description));
        }
    
        @Override
        protected void failed(final Throwable e, final Description description) {
            logger.info(String.format("Failed: %s", description), e);
        }
    
        @Override
        protected void starting(final Description description) {
            logger.info(String.format("Starting: %s", description));
        }
    
        @Override
        protected void finished(final Description description) {
            logger.info(String.format("Finished: %s", description));
        }
    
        };
    

    如果你想把它写在某个地方,Log4J 会做得很好,就像你已经做过的那样。就个人而言,我会通过文件配置它而不使用根记录器,但这只是一个细节。

    【讨论】:

    • 2015-08-12 15:29:17,828 INFO [GenericTaskInterpreterTests.setUp] ####### Starting test cases... #######。这是写入日志文件的行,而不是 succeededfailedstartingfinished 方法中的消息。
    • 您可能遇到了我们最近遇到的同样问题:extends Testcase 似乎导致使用 JUnit 3.8 Runner 执行您的测试。您可以删除 extends Testcase(并明确使用 Assert.assertNotNull 等,可能使用静态导入)或者您可以将 @RunWith(BlockJUnit4ClassRunner.class) 行添加到您的测试类中。有关类似问题,请参阅此帖子:stackoverflow.com/questions/31904380/…
    • 谢谢弗洛里安。我只是按照你的建议做了,它运行良好。这是working code 的要点。如果我理解正确的话,注解@RunWith(BlockJUnit4ClassRunner.class) 的重要性相对而言比删除extends TestCase 的意义要小。
    • 你可能不需要两者,真的。只需删除 extends TestCase 就足以让它与最新的 Runner 一起运行。如果您想保留扩展,@RunWith 只是一种可能性。就我个人而言,我只在真正需要时才尝试使用@RunWith,不需要弄乱代码。
    猜你喜欢
    • 2020-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多