如何将Boost.Test输出记录到HRF中的stdout和XML中的文件?

问题描述:

我想启用记录Boost.Test输出到 stdout/sterr和日志文件。如何将Boost.Test输出记录到HRF中的stdout和XML中的文件?

但是,我也希望stdout日志记录在HumanReadableFormat中,只有文件输出是XML格式。

生成报告文件似乎要处理here。 (official docs

选择格式可以在various ways中完成,但似乎有人被卡住了HRF或XML?


理由:

运行当在测试或Jenkins服务器时,xUnit pluginrequires日志 XML输出(而不是在报告 XML输出 - log_levelreport_level)。

但是,正在进行的日志输出(HRF)非常有价值测试正在服务器上运行,以检测悬挂测试或快速手动检查当前测试的位置。所以我想要一个正在进行的HRF日志进行测试,最后我需要一个包含Boost.Test(不是<TestResult>输出)的<TestLog>...</TestLog>输出的XML文件。

请注意,我们通过Boost.Test同时运行单元以及集成测试,因此其中一些运行时间相当长。

+1

在升压1.62实施,请参见[更改日志](http://live.boost.org/doc/libs/1_62_0/libs/test/doc/html/boost_test/change_log.html)。 – Raffi 2016-10-09 22:28:12

+0

@Raffi - 欢呼起来。现在我只需要从1.44升到1.62 :-D – 2016-10-10 08:47:39

+1

升级之前,1.62有一个错误,它会阻止为日志和报告文件设置文件。更好的是你等待更多的1.63(已经在开发分支中修复)。 – Raffi 2016-10-10 13:02:34

我已经做到了:-)经过大量的试验和错误之后,我设法找到了一种体面的方法,让Boost.Test框架本身完成实际的输出工作,并仍然将XML输出转换为文件。

,关键是要了解什么,以及如何输出可在如Boost.Test定制:

  • 有两个日志区,试验记录和检测结果,只有测试日志是有用的,因为测试结果,即使在最高细节层次仅仅是一个总结
  • 如Boost.Test仅支持其输出一个单个输出流,所以更换一个不立即帮助,虽然一个可以使用boost::iostreamtee_filter写入标准输出和文件。
  • 以上并没有帮助,因为Boost.Test也只使用一个 sinlge日志格式化程序(unit_test_log_formatter),所以即使您可以将输出分成两个流,仍然存在只有一种格式的问题。
  • 但是,日志格式化程序可以通过boost::unit_test::unit_test_log.set_formatter进行设置,这正是我正在做的。

我对HRF格式化程序以及XML格式化程序提供了一个精简包装,其中HRF格式化程序只记录到默认流,XML格式化程序写入到自定义XML文件。

它似乎运作良好,但使用需要您自担风险,因为这是相当新颖的,并且尚未在所有套件上运行。

#pragma once 

// Copyright (c) 2014 
// This file is distributed under the 
// Boost Software License - Version 1.0 - August 17th, 2003 
// (See http://www.boost.org/LICENSE_1_0.txt) 

#include <boost/test/unit_test_log_formatter.hpp> 
#include <boost/test/output/compiler_log_formatter.hpp> 
#include <boost/test/output/xml_log_formatter.hpp> 
#include <fstream> 

namespace boost { 
namespace unit_test { 
namespace output { 

//! Log formatter for Boost.Test that outputs the logging output *both* 
//! to the standard HRF formatter (normal output stream ~ cout) *and* 
//! also to the XML formatter, but the XML is written to a report file. 
//! 
//! Usage: 
//! // Call in init_unit_test_suite: (this will override the --log_format parameter) 
//! boost::unit_test::unit_test_log.set_formatter(
//! new boost::unit_test::output::dual_log_formatter(L"filename.xml") 
//!); 
//! 
//! Note: Calling `boost::unit_test::unit_test_log.set_stream(...)` will change the stream for 
//!  the HRF formatter used here. 
//! 
//! Note: Implemented in boost::unit_test::output for symmetry with existing formatter classes 
//! 
class dual_log_formatter : public unit_test_log_formatter { 
public: 
    // Formatter interface 
    void log_start(std::ostream& os, counter_t test_cases_amount) override { 
     hrf_logger.log_start(os, test_cases_amount); 
     xml_logger.log_start(xml_file, test_cases_amount); 
    } 
    void log_finish(std::ostream& os) override { 
     hrf_logger.log_finish(os); 
     xml_logger.log_finish(xml_file); 
    } 
    void log_build_info(std::ostream& os) override { 
     hrf_logger.log_build_info(os); 
     xml_logger.log_build_info(xml_file); 
    } 

    void test_unit_start(std::ostream& os, test_unit const& tu) override { 
     hrf_logger.test_unit_start(os, tu); 
     xml_logger.test_unit_start(xml_file, tu); 
    } 

    void test_unit_finish(std::ostream& os, test_unit const& tu, unsigned long elapsed) override { 
     hrf_logger.test_unit_finish(os, tu, elapsed); 
     xml_logger.test_unit_finish(xml_file, tu, elapsed); 
    } 

    void test_unit_skipped(std::ostream& os, test_unit const& tu) override { 
     hrf_logger.test_unit_skipped(os, tu); 
     xml_logger.test_unit_skipped(xml_file, tu); 
    } 

    void log_exception(std::ostream& os, log_checkpoint_data const& checkpoint_data, execution_exception const& ex) override { 
     hrf_logger.log_exception(os, checkpoint_data, ex); 
     xml_logger.log_exception(xml_file, checkpoint_data, ex); 
    } 

    void log_entry_start(std::ostream& os, log_entry_data const& entry_data, log_entry_types let) override { 
     hrf_logger.log_entry_start(os, entry_data, let); 
     xml_logger.log_entry_start(xml_file, entry_data, let); 
    } 
    using unit_test_log_formatter::log_entry_value; // bring base class functions into overload set 
    void log_entry_value(std::ostream& os, const_string value) override { 
     hrf_logger.log_entry_value(os, value); 
     xml_logger.log_entry_value(xml_file, value); 
    } 
    void log_entry_finish(std::ostream& os) override { 
     hrf_logger.log_entry_finish(os); 
     xml_logger.log_entry_finish(xml_file); 
    } 

    dual_log_formatter(const wchar_t* xmlFilename) { // Note: Use char* on non-MSVC compilers 
     xml_file.open(xmlFilename); 
    } 

private: 
    std::ofstream xml_file; 
    compiler_log_formatter hrf_logger; 
    xml_log_formatter xml_logger; 
}; 

} 
} 
}