Repository: boostcon/cppnow_presentations_2014 Branch: master Commit: 46107645315b Files: 476 Total size: 46.9 MB Directory structure: gitextract_igkvdt0q/ ├── .gitignore ├── README.md └── files/ ├── ConceptClang.pptx ├── CppNow2014Ranges.odp ├── PracticalTypeErasureSlides.odp ├── bounded_integer.odp ├── cxx11-library-design.pptx ├── functional-data-structures.key ├── open-pattern-matching.pptx ├── optimization_boost_asio.key ├── ownership_of_memory.odp ├── test_driven/ │ ├── Boost.Test Documentation Rewrite/ │ │ ├── doc/ │ │ │ └── src/ │ │ │ └── boostbook.css │ │ ├── index.html │ │ └── libs/ │ │ └── test/ │ │ └── doc/ │ │ ├── Jamfile.v2 │ │ ├── html/ │ │ │ ├── index.html │ │ │ ├── test/ │ │ │ │ ├── guide/ │ │ │ │ │ ├── acceptance_tests.html │ │ │ │ │ ├── compilation/ │ │ │ │ │ │ ├── _main_.html │ │ │ │ │ │ ├── header_only.html │ │ │ │ │ │ ├── minimal_header.html │ │ │ │ │ │ ├── shared_library.html │ │ │ │ │ │ └── static_library.html │ │ │ │ │ ├── compilation.html │ │ │ │ │ ├── exception_safety_test.html │ │ │ │ │ ├── manually_registering_test_cases_and_suites.html │ │ │ │ │ ├── mocking_collaborators.html │ │ │ │ │ ├── test_case_design.html │ │ │ │ │ ├── testing__main_.html │ │ │ │ │ ├── testing_file_i_o.html │ │ │ │ │ ├── testing_file_io.html │ │ │ │ │ └── testing_protected_or_private_members.html │ │ │ │ ├── guide.html │ │ │ │ ├── how_to_read_this_documentation.html │ │ │ │ ├── motivation.html │ │ │ │ ├── reference/ │ │ │ │ │ ├── assertion/ │ │ │ │ │ │ ├── _boost____level___bitwise_equal_.html │ │ │ │ │ │ ├── _boost____level___close_.html │ │ │ │ │ │ ├── _boost____level___close_fraction_.html │ │ │ │ │ │ ├── _boost____level___equal_collections_.html │ │ │ │ │ │ ├── _boost____level___exception_.html │ │ │ │ │ │ ├── _boost____level___ge_.html │ │ │ │ │ │ ├── _boost____level___gt_.html │ │ │ │ │ │ ├── _boost____level___le_.html │ │ │ │ │ │ ├── _boost____level___lt_.html │ │ │ │ │ │ ├── _boost____level___message_.html │ │ │ │ │ │ ├── _boost____level___ne_.html │ │ │ │ │ │ ├── _boost____level___no_throw_.html │ │ │ │ │ │ ├── _boost____level___predicate_.html │ │ │ │ │ │ ├── _boost____level___small_.html │ │ │ │ │ │ ├── _boost_test_dont_print_log_value_.html │ │ │ │ │ │ ├── _boost_test_error_.html │ │ │ │ │ │ ├── _boost_test_is_defined_.html │ │ │ │ │ │ ├── boost_fail.html │ │ │ │ │ │ ├── boost_level_equal.html │ │ │ │ │ │ ├── boost_level_exception.html │ │ │ │ │ │ ├── boost_level_message.html │ │ │ │ │ │ ├── boost_level_no_throw.html │ │ │ │ │ │ ├── boost_level_throw.html │ │ │ │ │ │ ├── boost_test_dont_print_log_value.html │ │ │ │ │ │ └── levels.html │ │ │ │ │ ├── assertion.html │ │ │ │ │ ├── configuration_macros.html │ │ │ │ │ ├── headers.html │ │ │ │ │ ├── runner/ │ │ │ │ │ │ ├── argument/ │ │ │ │ │ │ │ ├── ___break_exec_path_.html │ │ │ │ │ │ │ ├── ___build_info_.html │ │ │ │ │ │ │ ├── ___catch_system_errors_.html │ │ │ │ │ │ │ ├── ___color_output_.html │ │ │ │ │ │ │ ├── ___detect_fp_exceptions_.html │ │ │ │ │ │ │ ├── ___detect_memory_leaks_.html │ │ │ │ │ │ │ ├── ___log_level_.html │ │ │ │ │ │ │ ├── ___log_sink_.html │ │ │ │ │ │ │ ├── ___output_format_.html │ │ │ │ │ │ │ ├── ___random_.html │ │ │ │ │ │ │ ├── ___report_level_.html │ │ │ │ │ │ │ ├── ___report_sink_.html │ │ │ │ │ │ │ ├── ___result_code_.html │ │ │ │ │ │ │ ├── ___save_pattern_.html │ │ │ │ │ │ │ ├── ___show_progress_.html │ │ │ │ │ │ │ ├── ___use_alt_stack_.html │ │ │ │ │ │ │ ├── auto_start_dbg.html │ │ │ │ │ │ │ ├── list_content.html │ │ │ │ │ │ │ ├── log_format.html │ │ │ │ │ │ │ ├── log_level.html │ │ │ │ │ │ │ ├── log_sink.html │ │ │ │ │ │ │ ├── output_format.html │ │ │ │ │ │ │ ├── report_format.html │ │ │ │ │ │ │ ├── report_level.html │ │ │ │ │ │ │ ├── report_sink.html │ │ │ │ │ │ │ └── run_test.html │ │ │ │ │ │ ├── argument.html │ │ │ │ │ │ ├── output/ │ │ │ │ │ │ │ ├── _boost_test_checkpoint_.html │ │ │ │ │ │ │ ├── _boost_test_passpoint_.html │ │ │ │ │ │ │ ├── boost_test_checkpoint.html │ │ │ │ │ │ │ ├── boost_test_message.html │ │ │ │ │ │ │ ├── log.html │ │ │ │ │ │ │ ├── report.html │ │ │ │ │ │ │ ├── test_log.html │ │ │ │ │ │ │ └── test_report.html │ │ │ │ │ │ └── output.html │ │ │ │ │ ├── runner.html │ │ │ │ │ ├── test_case/ │ │ │ │ │ │ ├── boost_auto_test_case.html │ │ │ │ │ │ ├── boost_auto_test_case_expected_failures.html │ │ │ │ │ │ ├── boost_auto_test_case_template.html │ │ │ │ │ │ ├── boost_fixture_test_case.html │ │ │ │ │ │ ├── boost_global_fixture.html │ │ │ │ │ │ ├── boost_param_class_test_case.html │ │ │ │ │ │ ├── boost_param_test_case.html │ │ │ │ │ │ ├── boost_test_case.html │ │ │ │ │ │ ├── boost_test_case_template.html │ │ │ │ │ │ └── boost_test_case_template_function.html │ │ │ │ │ ├── test_case.html │ │ │ │ │ ├── test_classes/ │ │ │ │ │ │ ├── assertion/ │ │ │ │ │ │ │ ├── _boost____level___bitwise_equal_.html │ │ │ │ │ │ │ ├── _boost____level___close_.html │ │ │ │ │ │ │ ├── _boost____level___close_fraction_.html │ │ │ │ │ │ │ ├── _boost____level___equal_collections_.html │ │ │ │ │ │ │ ├── _boost____level___exception_.html │ │ │ │ │ │ │ ├── _boost____level___ge_.html │ │ │ │ │ │ │ ├── _boost____level___gt_.html │ │ │ │ │ │ │ ├── _boost____level___le_.html │ │ │ │ │ │ │ ├── _boost____level___lt_.html │ │ │ │ │ │ │ ├── _boost____level___message_.html │ │ │ │ │ │ │ ├── _boost____level___ne_.html │ │ │ │ │ │ │ ├── _boost____level___no_throw_.html │ │ │ │ │ │ │ ├── _boost____level___predicate_.html │ │ │ │ │ │ │ ├── _boost____level___small_.html │ │ │ │ │ │ │ ├── _boost_test_dont_print_log_value_.html │ │ │ │ │ │ │ ├── _boost_test_error_.html │ │ │ │ │ │ │ ├── _boost_test_is_defined_.html │ │ │ │ │ │ │ ├── boost_fail.html │ │ │ │ │ │ │ ├── boost_level_equal.html │ │ │ │ │ │ │ ├── boost_level_throw.html │ │ │ │ │ │ │ └── levels.html │ │ │ │ │ │ ├── assertion.html │ │ │ │ │ │ ├── headers.html │ │ │ │ │ │ ├── init_unit_test_func.html │ │ │ │ │ │ ├── master_test_suite_t.html │ │ │ │ │ │ ├── predicate_result/ │ │ │ │ │ │ │ ├── init_unit_test_func.html │ │ │ │ │ │ │ ├── master_test_suite_t.html │ │ │ │ │ │ │ ├── test_case.html │ │ │ │ │ │ │ ├── test_observer.html │ │ │ │ │ │ │ ├── test_suite.html │ │ │ │ │ │ │ ├── test_unit.html │ │ │ │ │ │ │ ├── unit_test_log_formatter.html │ │ │ │ │ │ │ ├── unit_test_log_t.html │ │ │ │ │ │ │ └── unit_test_main.html │ │ │ │ │ │ ├── predicate_result.html │ │ │ │ │ │ ├── runner/ │ │ │ │ │ │ │ ├── argument.html │ │ │ │ │ │ │ └── output.html │ │ │ │ │ │ ├── runner.html │ │ │ │ │ │ ├── test_case.html │ │ │ │ │ │ ├── test_observer.html │ │ │ │ │ │ ├── test_suite.html │ │ │ │ │ │ ├── test_unit.html │ │ │ │ │ │ ├── unit_test_log_formatter.html │ │ │ │ │ │ ├── unit_test_log_t.html │ │ │ │ │ │ └── unit_test_main.html │ │ │ │ │ ├── test_classes.html │ │ │ │ │ ├── test_suite/ │ │ │ │ │ │ ├── boost_auto_test_suite.html │ │ │ │ │ │ ├── boost_auto_test_suite_end.html │ │ │ │ │ │ ├── boost_fixture_test_suite.html │ │ │ │ │ │ ├── boost_test_module.html │ │ │ │ │ │ └── boost_test_suite.html │ │ │ │ │ └── test_suite.html │ │ │ │ ├── reference.html │ │ │ │ ├── tutorials/ │ │ │ │ │ ├── hello_test.html │ │ │ │ │ ├── running_selected_tests.html │ │ │ │ │ ├── testing_with_exceptions.html │ │ │ │ │ └── testing_with_fixtures.html │ │ │ │ └── tutorials.html │ │ │ └── test_HTML.manifest │ │ ├── src/ │ │ │ ├── Jamfile.v2 │ │ │ ├── UTF.log.xsd │ │ │ ├── UTF.report.xsd │ │ │ ├── examples/ │ │ │ │ ├── Jamfile.v2 │ │ │ │ ├── another_global_fixture.cpp │ │ │ │ ├── assertion_failures.cpp │ │ │ │ ├── assertions.cpp │ │ │ │ ├── auto_test_case_expected_failures.cpp │ │ │ │ ├── auto_test_case_template.cpp │ │ │ │ ├── compilation/ │ │ │ │ │ ├── Jamfile.v2 │ │ │ │ │ ├── dynamic/ │ │ │ │ │ │ ├── main.cpp │ │ │ │ │ │ └── test_hello.cpp │ │ │ │ │ ├── dynamic_main/ │ │ │ │ │ │ ├── main.cpp │ │ │ │ │ │ └── test_hello.cpp │ │ │ │ │ ├── minimal/ │ │ │ │ │ │ └── test_hello.cpp │ │ │ │ │ ├── static/ │ │ │ │ │ │ ├── main.cpp │ │ │ │ │ │ └── test_hello.cpp │ │ │ │ │ └── static_main/ │ │ │ │ │ ├── main.cpp │ │ │ │ │ └── test_hello.cpp │ │ │ │ ├── file_system.cpp │ │ │ │ ├── global_fixture.cpp │ │ │ │ ├── manual_registration.cpp │ │ │ │ ├── param_class_test_case.cpp │ │ │ │ ├── param_test_case.cpp │ │ │ │ ├── test_case.cpp │ │ │ │ ├── test_case_template.cpp │ │ │ │ └── turtle_mock.cpp │ │ │ ├── ref-assertion.qbk │ │ │ ├── ref-assertion.qbk.bak │ │ │ ├── ref-compilation.qbk │ │ │ ├── ref-runner-argument.qbk │ │ │ ├── ref-runner-argument.qbk.bak │ │ │ ├── ref-runner-output.qbk │ │ │ ├── ref-runner.qbk │ │ │ ├── ref-test-case.qbk │ │ │ ├── ref-test-case.qbk.bak │ │ │ ├── ref-test-classes.qbk │ │ │ ├── ref-test-suite.qbk │ │ │ ├── reference.qbk │ │ │ ├── system_under_test/ │ │ │ │ ├── Jamfile.v2 │ │ │ │ ├── hello/ │ │ │ │ │ ├── Jamfile.v2 │ │ │ │ │ ├── hello.cpp │ │ │ │ │ └── hello.hpp │ │ │ │ └── scanner/ │ │ │ │ ├── Jamfile.v2 │ │ │ │ ├── directory_scanner.hpp │ │ │ │ ├── filesystem_directory_scanner.hpp │ │ │ │ ├── scanner.cpp │ │ │ │ └── scanner.hpp │ │ │ ├── test.qbk │ │ │ ├── tutorials/ │ │ │ │ ├── Jamfile.v2 │ │ │ │ ├── hello_test/ │ │ │ │ │ ├── 1/ │ │ │ │ │ │ ├── Jamfile.v2 │ │ │ │ │ │ ├── hello_test~1.output │ │ │ │ │ │ ├── sut/ │ │ │ │ │ │ │ ├── hello.cpp │ │ │ │ │ │ │ └── hello.hpp │ │ │ │ │ │ └── test/ │ │ │ │ │ │ └── test_hello.cpp │ │ │ │ │ ├── 2/ │ │ │ │ │ │ ├── Jamfile.v2 │ │ │ │ │ │ ├── hello_test~2.output │ │ │ │ │ │ ├── sut/ │ │ │ │ │ │ │ ├── hello.cpp │ │ │ │ │ │ │ └── hello.hpp │ │ │ │ │ │ └── test/ │ │ │ │ │ │ └── test_hello.cpp │ │ │ │ │ ├── 3/ │ │ │ │ │ │ ├── Jamfile.v2 │ │ │ │ │ │ ├── hello_test~3.output │ │ │ │ │ │ ├── sut/ │ │ │ │ │ │ │ ├── hello.cpp │ │ │ │ │ │ │ └── hello.hpp │ │ │ │ │ │ └── test/ │ │ │ │ │ │ └── test_hello.cpp │ │ │ │ │ ├── Jamfile.v2 │ │ │ │ │ ├── hello_test.output │ │ │ │ │ ├── sut/ │ │ │ │ │ │ ├── hello.cpp │ │ │ │ │ │ └── hello.hpp │ │ │ │ │ └── test/ │ │ │ │ │ └── test_hello.cpp │ │ │ │ ├── running_selected_tests/ │ │ │ │ │ ├── 1/ │ │ │ │ │ │ ├── Jamfile.v2 │ │ │ │ │ │ ├── report_level_detailed.output │ │ │ │ │ │ ├── sut/ │ │ │ │ │ │ │ ├── hello.cpp │ │ │ │ │ │ │ └── hello.hpp │ │ │ │ │ │ ├── test/ │ │ │ │ │ │ │ └── test_hello.cpp │ │ │ │ │ │ └── test_hello~running_selected_tests~1.output │ │ │ │ │ ├── 2/ │ │ │ │ │ │ ├── Jamfile.v2 │ │ │ │ │ │ ├── report_level_detailed.output │ │ │ │ │ │ ├── run_test_hello_inserts_text.output │ │ │ │ │ │ ├── run_test_hello_star_inserts_text.output │ │ │ │ │ │ ├── sut/ │ │ │ │ │ │ │ ├── hello.cpp │ │ │ │ │ │ │ └── hello.hpp │ │ │ │ │ │ ├── test/ │ │ │ │ │ │ │ └── test_hello.cpp │ │ │ │ │ │ └── test_hello~running_selected_tests~2.output │ │ │ │ │ ├── Jamfile.v2 │ │ │ │ │ ├── report_level_detailed.output │ │ │ │ │ ├── sut/ │ │ │ │ │ │ ├── hello.cpp │ │ │ │ │ │ └── hello.hpp │ │ │ │ │ └── test/ │ │ │ │ │ └── test_hello.cpp │ │ │ │ ├── testing_with_exceptions/ │ │ │ │ │ ├── 1/ │ │ │ │ │ │ ├── Jamfile.v2 │ │ │ │ │ │ ├── sut/ │ │ │ │ │ │ │ ├── hello.cpp │ │ │ │ │ │ │ └── hello.hpp │ │ │ │ │ │ ├── test/ │ │ │ │ │ │ │ └── test_hello.cpp │ │ │ │ │ │ └── test_hello~testing_with_exceptions~1.output │ │ │ │ │ ├── 2/ │ │ │ │ │ │ ├── Jamfile.v2 │ │ │ │ │ │ ├── sut/ │ │ │ │ │ │ │ ├── hello.cpp │ │ │ │ │ │ │ └── hello.hpp │ │ │ │ │ │ ├── test/ │ │ │ │ │ │ │ └── test_hello.cpp │ │ │ │ │ │ └── test_hello~testing_with_exceptions~2.output │ │ │ │ │ ├── Jamfile.v2 │ │ │ │ │ ├── sut/ │ │ │ │ │ │ ├── hello.cpp │ │ │ │ │ │ └── hello.hpp │ │ │ │ │ ├── test/ │ │ │ │ │ │ └── test_hello.cpp │ │ │ │ │ └── test_hello~testing_with_exceptions.output │ │ │ │ └── testing_with_fixtures/ │ │ │ │ ├── 1/ │ │ │ │ │ ├── Jamfile.v2 │ │ │ │ │ ├── sut/ │ │ │ │ │ │ ├── hello.cpp │ │ │ │ │ │ └── hello.hpp │ │ │ │ │ └── test/ │ │ │ │ │ └── test_hello.cpp │ │ │ │ ├── Jamfile.v2 │ │ │ │ ├── sut/ │ │ │ │ │ ├── hello.cpp │ │ │ │ │ └── hello.hpp │ │ │ │ └── test/ │ │ │ │ └── test_hello.cpp │ │ │ ├── tutorials.qbk │ │ │ ├── user-compilation.qbk │ │ │ └── user-guide.qbk │ │ └── todo.txt │ ├── ReadMe.txt │ └── snapshots/ │ ├── 00/ │ │ ├── CMakeLists.txt │ │ ├── LocalPaths.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 01/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 02/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 03/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 04/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 05/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 06/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 07/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 08/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 09/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 10/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 11/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 12/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 13/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 14/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 15/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 16/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 17/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 18/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 19/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 20/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 21/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 22/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 23/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 24/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ └── test_factors.cpp │ ├── 25/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ └── factors.h │ │ └── test/ │ │ ├── test_factors.cpp │ │ └── test_mediator.cpp │ ├── 26/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ ├── factors.h │ │ │ └── mediator.h │ │ └── test/ │ │ ├── test_factors.cpp │ │ └── test_mediator.cpp │ ├── 27/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ ├── factors.h │ │ │ └── mediator.h │ │ └── test/ │ │ ├── test_factors.cpp │ │ └── test_mediator.cpp │ ├── 28/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ ├── factors.h │ │ │ └── mediator.h │ │ └── test/ │ │ ├── test_factors.cpp │ │ └── test_mediator.cpp │ ├── 29/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ ├── factors.h │ │ │ └── mediator.h │ │ └── test/ │ │ ├── test_factors.cpp │ │ └── test_mediator.cpp │ ├── 30/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ ├── factors.h │ │ │ └── mediator.h │ │ └── test/ │ │ ├── test_factors.cpp │ │ └── test_mediator.cpp │ ├── 31/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ ├── factors.h │ │ │ └── mediator.h │ │ └── test/ │ │ ├── test_factors.cpp │ │ └── test_mediator.cpp │ ├── 32/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ ├── factors.h │ │ │ └── mediator.h │ │ └── test/ │ │ ├── test_factors.cpp │ │ └── test_mediator.cpp │ ├── 33/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ ├── factors.h │ │ │ └── mediator.h │ │ └── test/ │ │ ├── test_factors.cpp │ │ └── test_mediator.cpp │ ├── 34/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ ├── factors.h │ │ │ └── mediator.h │ │ └── test/ │ │ ├── test_factors.cpp │ │ └── test_mediator.cpp │ ├── 35/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ ├── factors.h │ │ │ └── mediator.h │ │ └── test/ │ │ ├── test_factors.cpp │ │ └── test_mediator.cpp │ ├── 36/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ ├── factors.h │ │ │ └── mediator.h │ │ └── test/ │ │ ├── test_factors.cpp │ │ └── test_mediator.cpp │ ├── 37/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ ├── factors.h │ │ │ └── mediator.h │ │ └── test/ │ │ ├── test_factors.cpp │ │ └── test_mediator.cpp │ ├── 38/ │ │ ├── CMakeLists.txt │ │ ├── factors/ │ │ │ ├── factors.cpp │ │ │ ├── factors.h │ │ │ └── mediator.h │ │ └── test/ │ │ ├── test_factors.cpp │ │ └── test_mediator.cpp │ └── 39/ │ ├── CMakeLists.txt │ ├── factors/ │ │ ├── factors.cpp │ │ ├── factors.h │ │ └── mediator.h │ └── test/ │ ├── test_factors.cpp │ └── test_mediator.cpp └── unicode-cpp.pptx ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ unlinked/ *~ .DS_Store ================================================ FILE: README.md ================================================ # C++Now 2014 Presentations * [Library in a Week Repo](https://github.com/JeffGarland/liaw2014.git) Below are links to the pdfs / keynotes / OPDs in the files directory. Depending on your browser, you may need to right click on the link and select save. ## Tuesday, May 13 * [Library in a Week - C++ Templating Engine](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/liaw_template_engine_day1.pdf?raw=true) * Keynote: Axiomatic Programming: From Euclidean Deductions to C++ Templates and Beyond * C++14: Through the Looking Glass * [Coroutines, Fibers, and Threads, Oh My](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/Coroutines-Fibers-Threads.pdf?raw=true) * The Canonical Class * [ConceptClang: Theoretical Advances with Full C++ Concepts](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/ConceptClang.pdf?raw=true) | [PPTX](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/ConceptClang.pptx?raw=true) * [Generic Programming of Generic Spaces: Compile-Time Geometric Algebra with C++11](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/generic_spaces.pdf?raw=true) * [Test-Driven Development With Boost.Test and Turtle Mock, Part I/II](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/test_driven/test_driven.pdf?raw=true) | [Code](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/test_driven/) * [Removing undefined behavior from integer operations: the bounded::integer library](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/bounded_integer.pdf?raw=true) | [LibreOffice File](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/bounded_integer.opd?raw=true) * [Value Semantics and Range Algorithms - Composability and Efficiency](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/range_algos.pdf?raw=true) * Preparing the C++11 Library AFIO for Boost Peer Review ## Wednesday, May 14 * [MPL11: A New Metaprogramming Library for C++11](https://ldionne.github.io/mpl11-cppnow-2014) * [The Optimization of a Boost.Asio-Based Networking Server](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/optimization_boost_asio.pdf?raw=true) | [Keynote File](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/optimization_boost_asio.key?raw=true) * [Undefined Behavior in C++; what is it, and why should I care](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/Undefined-Behavior.pdf?raw=true) * [Mach7: The Design and Evolution of a Pattern Matching Library for C++](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/open-pattern-matching.pdf?raw=true) | [PowerPoint File](ttps://github.com/boostcon/cppnow_presentations_2014/blob/master/files/open-pattern-matching.pptx?raw=true) * [Practical Type Erasure: A boost::any Based Configuration Framework](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/PracticalTypeErasureSlides.pdf?raw=true) | [LibreOffice File](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/PracticalTypeErasureSlides.odp?raw=true) * [A Tutorial Introduction to C++11/14 Part I/II](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/tutorial_intro_cpp_11_14.pdf?raw=true) * [C++11 in Space Plasma Model Development](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/esitys.tar?raw=true) (Requires Java) * [C++11 Library Design](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/cxx11-library-design.pdf?raw=true) | [PPTX File](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/cxx11-library-design.pptx?raw=true) * [Goals for Better Code: Implement Complete Types](https://github.com/sean-parent/sean-parent.github.com/wiki/Papers-and-Presentations) * [Multiplatform C++](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/2014_05_14_multiplatform_cpp.pdf?raw=true) * Octopus: A Policy-Driven Framework for CFD Simulations ## Thursday, May 15 * [Keynote: Beware of C++](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/Josuttis_C++Now_140515_handouts.pdf?raw=true) * [Interactive Metaprogramming Shell Based on Clang](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/2014_cppnow_metashell.pdf?raw=true) * [libcppa: Type-safe Messaging Systems in C++](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/libcppa_part1.pdf?raw=true) | [Part II](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/libcppa_part2.pdf?raw=true) * [Unicode in C++](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/unicode-cpp.pdf?raw=true) | [PPTX File](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/unicode-cpp.pptx?raw=true) * [CppComponents: A Modern Portable C++11 Component System](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/cppnow2014_bandela_presentation.pdf?raw=true) * [UI. Aesthetics. C++](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/UI_Aesthetics_Cpp.pdf?raw=true) * Accelerator Programming with C++ AMP * [Designing XML API for Modern C++](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/designing-xml-api-for-modern-c++.pdf?raw=true) * [Modern C++ as Concurrent Assembly](https://github.com/diegoperini/cppnow2014-doppl) * [Understanding &&](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/UnderstandingRValueRef_rev7.pdf?raw=true) * [Boost Library Incubator](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/incubator.pdf?raw=true) | [Zip Archive](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/incubator.zip?raw=true) ## Friday, May 16 * [Iterators May Stay](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/CppNow2014Ranges.pdf?raw=true) | [LibreOffice File](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/CppNow2014Ranges.opd?raw=true) * [Value Semantics: It ain't about the syntax!](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/accu2015.140518.pdf?raw=true) * [Create Your Own Refactoring Tool with Clang](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/Create-Your-Own-Refactoring-Tool-with-Clang.pdf?raw=true) * [How to Design C++ Implementations of Complex Combinatorial Algorithms](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/How_to_Design_C++_Implementations_of_Complex_Combinatorial_Algorithms.pdf?raw=true) * [Intro to Functional Programming in C++](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/intro-to-functional-programming-in-cpp.pdf?raw=true) * [Managing Object Lifetimes](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/Managing-Object-Lifetimes.pdf?raw=true) * [0xBADC0DE](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/0xBADC0DE.pdf?raw=true) * [Expected — An Exception-friendly Error Monad](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/expected.pdf?raw=true) * [Lifetime and Usage of Global, Thread-local, and Static Data](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/LifetimeRev2.pdf?raw=true) * [Functional Data Structures in C++](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/functional-data-structures.pdf?raw=true) | [Keynote File](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/functional-data-structures.key?raw=true) * [Asynchronous Programming Using Boost.MetaStateMachine and the Upcoming Asynchronous Library](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/AsyncTalkCppNow14.pdf?raw=true) * [Ownership of Memory in C++](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/ownership_of_memory.pdf?raw=true) | [LibreOffice File](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/ownership_of_memory.opd?raw=true) ## Saturday, May 17 * [The Future of Accelerator Programming in C++](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/CppNow2014_Future_of_Accelerator_Programming.pdf?raw=true) * [Functional Reactive Programming - Cleanly Abstracted Interactivity](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/Functional-Reactive-Programming.pdf?raw=true) * [Disambiguation: The Black Technology](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/disambiguation.pdf?raw=true) * [My Thoughts on Large Code Base Change Ripple Management in C++](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/change_ripple.pdf?raw=true) | [Position Paper](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/large_code_base_change_ripple_in_cpp.pdf?raw=true) * [Future of Boost: Boostache](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/boostache.pdf?raw=true) * [Future of Boost: Community Management Team](https://github.com/boostcon/cppnow_presentations_2014/blob/master/files/boost-cmt.pdf?raw=true) ================================================ FILE: files/optimization_boost_asio.key ================================================ [File too large to display: 45.4 MB] ================================================ FILE: files/test_driven/Boost.Test Documentation Rewrite/doc/src/boostbook.css ================================================ /*============================================================================= Copyright (c) 2004 Joel de Guzman http://spirit.sourceforge.net/ Distributed under the Boost Software License, Version 1.0. (See accompany- ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ /*============================================================================= Body defaults =============================================================================*/ body { margin: 1em; font-family: sans-serif; } /*============================================================================= Paragraphs =============================================================================*/ p { text-align: left; font-size: 10pt; line-height: 1.15; } /*============================================================================= Program listings =============================================================================*/ /* Code on paragraphs */ p tt.computeroutput { font-size: 9pt; } pre.synopsis { font-size: 9pt; margin: 1pc 4% 0pc 4%; padding: 0.5pc 0.5pc 0.5pc 0.5pc; } .programlisting, .screen { font-size: 9pt; display: block; margin: 1pc 4% 0pc 4%; padding: 0.5pc 0.5pc 0.5pc 0.5pc; } /* Program listings in tables don't get borders */ td .programlisting, td .screen { margin: 0pc 0pc 0pc 0pc; padding: 0pc 0pc 0pc 0pc; } /*============================================================================= Headings =============================================================================*/ h1, h2, h3, h4, h5, h6 { text-align: left; margin: 1em 0em 0.5em 0em; font-weight: bold; } h1 { font-size: 140%; } h2 { font-weight: bold; font-size: 140%; } h3 { font-weight: bold; font-size: 130%; } h4 { font-weight: bold; font-size: 120%; } h5 { font-weight: normal; font-style: italic; font-size: 110%; } h6 { font-weight: normal; font-style: italic; font-size: 100%; } /* Top page titles */ title, h1.title, h2.title h3.title, h4.title, h5.title, h6.title, .refentrytitle { font-weight: bold; margin-bottom: 1pc; } h1.title { font-size: 140% } h2.title { font-size: 140% } h3.title { font-size: 130% } h4.title { font-size: 120% } h5.title { font-size: 110% } h6.title { font-size: 100% } .section h1 { margin: 0em 0em 0.5em 0em; font-size: 140%; } .section h2 { font-size: 140% } .section h3 { font-size: 130% } .section h4 { font-size: 120% } .section h5 { font-size: 110% } .section h6 { font-size: 100% } /* Code on titles */ h1 tt.computeroutput { font-size: 140% } h2 tt.computeroutput { font-size: 140% } h3 tt.computeroutput { font-size: 130% } h4 tt.computeroutput { font-size: 130% } h5 tt.computeroutput { font-size: 130% } h6 tt.computeroutput { font-size: 130% } /*============================================================================= Author =============================================================================*/ h3.author { font-size: 100% } /*============================================================================= Lists =============================================================================*/ li { font-size: 10pt; line-height: 1.3; } /* Unordered lists */ ul { text-align: left; } /* Ordered lists */ ol { text-align: left; } /*============================================================================= Links =============================================================================*/ a { text-decoration: none; /* no underline */ } a:hover { text-decoration: underline; } /*============================================================================= Spirit style navigation =============================================================================*/ .spirit-nav { text-align: right; } .spirit-nav a { color: white; padding-left: 0.5em; } .spirit-nav img { border-width: 0px; } /*============================================================================= Copyright footer =============================================================================*/ .copyright-footer { text-align: right; font-size: 70%; } .copyright-footer p { text-align: right; font-size: 80%; } /*============================================================================= Table of contents =============================================================================*/ div.toc { margin: 1pc 4% 0pc 4%; padding: 0.1pc 1pc 0.1pc 1pc; font-size: 80%; line-height: 1.15; } .boost-toc { float: right; padding: 0.5pc; } /* Code on toc */ .toc .computeroutput { font-size: 120% } /* No margin on nested menus */ .toc dl dl { margin: 0; } /*============================================================================= Tables =============================================================================*/ .table-title, div.table p.title { margin-left: 4%; padding-right: 0.5em; padding-left: 0.5em; } .informaltable table, .table table { width: 92%; margin-left: 4%; margin-right: 4%; } div.informaltable table, div.table table { padding: 4px; } /* Table Cells */ div.informaltable table tr td, div.table table tr td { padding: 0.5em; text-align: left; font-size: 9pt; } div.informaltable table tr th, div.table table tr th { padding: 0.5em 0.5em 0.5em 0.5em; border: 1pt solid white; font-size: 80%; } table.simplelist { width: auto !important; margin: 0em !important; padding: 0em !important; border: none !important; } table.simplelist td { margin: 0em !important; padding: 0em !important; text-align: left !important; font-size: 9pt !important; border: none !important; } /*============================================================================= Blurbs =============================================================================*/ div.note, div.tip, div.important, div.caution, div.warning, p.blurb { font-size: 9pt; /* A little bit smaller than the main text */ line-height: 1.2; display: block; margin: 1pc 4% 0pc 4%; padding: 0.5pc 0.5pc 0.5pc 0.5pc; } p.blurb img { padding: 1pt; } /*============================================================================= Variable Lists =============================================================================*/ div.variablelist { margin: 1em 0; } /* Make the terms in definition lists bold */ div.variablelist dl dt, span.term { font-weight: bold; font-size: 10pt; } div.variablelist table tbody tr td { text-align: left; vertical-align: top; padding: 0em 2em 0em 0em; font-size: 10pt; margin: 0em 0em 0.5em 0em; line-height: 1; } div.variablelist dl dt { margin-bottom: 0.2em; } div.variablelist dl dd { margin: 0em 0em 0.5em 2em; font-size: 10pt; } div.variablelist table tbody tr td p, div.variablelist dl dd p { margin: 0em 0em 0.5em 0em; line-height: 1; } /*============================================================================= Misc =============================================================================*/ /* Title of books and articles in bibliographies */ span.title { font-style: italic; } span.underline { text-decoration: underline; } span.strikethrough { text-decoration: line-through; } /* Copyright, Legal Notice */ div div.legalnotice p { text-align: left } /*============================================================================= Colors =============================================================================*/ @media screen { body { background-color: #FFFFFF; color: #000000; } /* Syntax Highlighting */ .keyword { color: #0000AA; } .identifier { color: #000000; } .special { color: #707070; } .preprocessor { color: #402080; } .char { color: teal; } .comment { color: #800000; } .string { color: teal; } .number { color: teal; } .white_bkd { background-color: #FFFFFF; } .dk_grey_bkd { background-color: #999999; } /* Links */ a, a .keyword, a .identifier, a .special, a .preprocessor a .char, a .comment, a .string, a .number { color: #005a9c; } a:visited, a:visited .keyword, a:visited .identifier, a:visited .special, a:visited .preprocessor a:visited .char, a:visited .comment, a:visited .string, a:visited .number { color: #9c5a9c; } h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited { text-decoration: none; /* no underline */ color: #000000; } /* Copyright, Legal Notice */ .copyright { color: #666666; font-size: small; } div div.legalnotice p { color: #666666; } /* Program listing */ pre.synopsis { border: 1px solid #DCDCDC; } .programlisting, .screen { border: 1px solid #DCDCDC; } td .programlisting, td .screen { border: 0px solid #DCDCDC; } /* Blurbs */ div.note, div.tip, div.important, div.caution, div.warning, p.blurb { border: 1px solid #DCDCDC; } /* Table of contents */ div.toc { border: 1px solid #DCDCDC; } /* Tables */ div.informaltable table tr td, div.table table tr td { border: 1px solid #DCDCDC; } div.informaltable table tr th, div.table table tr th { background-color: #F0F0F0; border: 1px solid #DCDCDC; } .copyright-footer { color: #8F8F8F; } /* Misc */ span.highlight { color: #00A000; } } @media print { /* Links */ a { color: black; } a:visited { color: black; } .spirit-nav { display: none; } /* Program listing */ pre.synopsis { border: 1px solid gray; } .programlisting, .screen { border: 1px solid gray; } td .programlisting, td .screen { border: 0px solid #DCDCDC; } /* Table of contents */ div.toc { border: 1px solid gray; } .informaltable table, .table table { border: 1px solid gray; border-collapse: collapse; } /* Tables */ div.informaltable table tr td, div.table table tr td { border: 1px solid gray; } div.informaltable table tr th, div.table table tr th { border: 1px solid gray; } table.simplelist tr td { border: none !important; } /* Misc */ span.highlight { font-weight: bold; } } /*============================================================================= Images =============================================================================*/ span.inlinemediaobject img { vertical-align: middle; } /*============================================================================== Super and Subscript: style so that line spacing isn't effected, see http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=1&postId=5341 ==============================================================================*/ sup, sub { height: 0; line-height: 1; vertical-align: baseline; position: relative; } /* For internet explorer: */ * html sup, * html sub { vertical-align: bottom; } sup { bottom: 1ex; } sub { top: .5ex; } /*============================================================================== Indexes: pretty much the same as the TOC. ==============================================================================*/ .index { font-size: 80%; padding-top: 0px; padding-bottom: 0px; margin-top: 0px; margin-bottom: 0px; margin-left: 0px; } .index ul { padding-left: 3em; } .index p { padding: 2px; margin: 2px; } .index-entry-level-0 { font-weight: bold; } .index em { font-weight: bold; } ================================================ FILE: files/test_driven/Boost.Test Documentation Rewrite/index.html ================================================
Browse the documentation.
================================================ FILE: files/test_driven/Boost.Test Documentation Rewrite/libs/test/doc/Jamfile.v2 ================================================ # Jamfile.v2 # # Copyright (c) 2013 # Richard Thomson # # Distributed Under the Boost Software License, Version 1.0. (See # accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) use-project /boost/test : ../build ; import quickbook ; build-project src ; alias code : src ; boostbook test : src/test.qbk code :![]() |
Home | Libraries | People | FAQ | More |
Copyright © 2013 Richard Thomson
Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Table of Contents
BOOST_level_BITWISE_EQUALBOOST_level_CLOSEBOOST_level_CLOSE_FRACTIONBOOST_level_EQUALBOOST_level_EQUAL_COLLECTIONSBOOST_level_EXCEPTIONBOOST_FAILBOOST_level_GEBOOST_level_GTBOOST_level_LEBOOST_level_LTBOOST_level_MESSAGEBOOST_level_NEBOOST_level_NO_THROWBOOST_level_PREDICATEBOOST_level_SMALLBOOST_level_THROWBOOST_TEST_DONT_PRINT_LOG_VALUEThis is the documentation for Boost.Test, a library designed to support automated testing of software generally and unit testing specifically.
Last revised: January 06, 2014 at 04:37:36 GMT |
![]() |
Home | Libraries | People | FAQ | More |
Unit testing helps us to find bugs "in the small"; little implementation details that we got wrong while we were building a function, a method or a class. When we test each class as an isolated unit, we can miss errors in the way two classes interact or in the way a whole ensemble of classes cooperate in an integrated system.
An acceptance test is an automated test that exercises our system as an integrated whole and not as a collection of isolated units. In a unit test, we decouple ourselves from the execution environment in order to test a piece of code in isolation. In an acceptance test, we run the whole system and provide controlled inputs to the system. This may consist of prepared input data files, prepared input databases and so-on.
Using these two forms of automated testing, we can use them as a vise to squeeze bugs between the two forms of automated tests. Unit tests push from below and acceptance tests push from above.
While the facilities in Boost.Test can be used to create an automated acceptance test, the tools are fairly low-level for the kinds of high-level criteria that an acceptance test would use. Acceptance tests are usually defined by the product owner or customer and will describe acceptance criteria in the language closest to the problem domain and farthest away from the details of the implementation.
A better approach for automated acceptance tests would be a tool such as FitNesse that is designed for automated acceptance testing.
![]() |
Home | Libraries | People | FAQ | More |
To use the implementation of main provided by Boost.Test,
exactly one source file must define BOOST_TEST_MAIN
before including <boost/test/unit_test.hpp>. If
multiple source files define BOOST_TEST_MAIN,
then a multiply defined symbol error will occur during linking.
If BOOST_TEST_NO_MAIN
is defined, then no implementation of main will be provided
and the test executable must provide an initialization function. The exact
initialization function that must be provided varies depending on how the
library is compiled. The details are shown in the discussion of each compilation
variation.
When Boost.Test is compiled as a library, BOOST_TEST_NO_MAIN
must be defined when the library is compiled for it to work properly in
those circumstances.
![]() |
Home | Libraries | People | FAQ | More |
The entire unit test framework can be incorporated into an executable by
including the file <boost/test/included/unit_test.hpp>.
Because the entire implementation is incorporated into the source file
including this header, only a single source file in the test executable
can include this header.
Additional source files must define BOOST_TEST_NO_LIB
before including <boost/test/unit_test.hpp> to
prevent any automatic linking to a shared library. If additional source
files attempt to include <boost/test/included/unit_test.hpp>,
a multiply defined symbol error will occur during linking.
// In exactly one source file: #include <boost/test/included/unit_test.hpp> // test cases (optional)
// In additional source files #define BOOST_TEST_NO_LIB #include <boost/test/unit_test.hpp> // test cases
If BOOST_TEST_NO_MAIN
is defined, then an implementation of main must be provided
that executes the test cases. This is most readily done by delegating to
unit_test_main.
// In exactly one source file #define BOOST_TEST_NO_MAIN #include <boost/test/unit_test.hpp> boost::unit_test::test_suite *init_function(int argc, char *argv[]) { // create test cases and suites and return a pointer to any enclosing // suite, or 0. return 0; } int main(int argc, char* argv[]) { return ::boost::unit_test::unit_test_main(&init_function, argc, argv); }
The tutorials all use the header-only version of Boost.Test.
![]() |
Home | Libraries | People | FAQ | More |
A lightweight, minimal version of the testing framework can be obtained
by including <boost/test/minimal.hpp>. This header
provides only the following macros:
|
Macro |
Meaning |
|---|---|
|
|
If expression is false, the test fails and test execution continues. |
|
|
If expression is false, the test fails and test execution terminates. |
|
|
Report message, fail the test and continue test execution. |
|
|
Report message, fail the test and terminate test execution. |
The header supplies an implementation of main that executes
a single test case by calling a free function named test_main
with the following signature:
int test_main(int argc, char *argv[]);
The arguments argc and argv are passed
to test_main from the implementation of main
supplied by the test framework. No command-line argument processing is
performed by main. A summary report of errors recorded
by the test case is printed out after executing the test case. If any exception
is thrown by the test case, it is caught by main and
treated as an error from the test case.
#include <boost/test/minimal.hpp> int test_main(int argc, char *argv[]) { // test case }
![]() |
Home | Libraries | People | FAQ | More |
To build Boost.Test as a shared library, first build the boost build tools,
as described in the Getting
Started documentation. After you have bootstrapped the build tools,
build the test library with by invoking b2 with arguments
similar to the following:
b2 --with-test link=shared
This will place the resulting libraries in stage/lib
at the top level of the boost tree.
In a shared library configuration, Boost.Test is compiled into a single
shared library named boost_unit_test_framework and the
test executable is linked against that library to import symbols from the
library. The Boost.Test shared library must be available to the runtime
loader in order for the tests to execute. Every compilation unit that includes
a header from Boost.Test must define BOOST_TEST_DYN_LINK
first so that declarations are properly annotated as imported symbols.
When BOOST_TEST_DYN_LINK
is defined, Boost.Test also defines BOOST_TEST_ALTERNATIVE_INIT_API.
Exactly one compilation unit in the test executable should define BOOST_TEST_MAIN,
in order run the tests.
// In exactly one compilation unit #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MAIN #include <boost/test/unit_test.hpp> // test cases (optional)
Additional source files define BOOST_TEST_DYN_LINK,
include the main unit test header and define more test cases and/or suites.
// In additional source files #define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> // test cases
To compile the library with no implementation of main,
add BOOST_TEST_NO_MAIN
to the cxxflags property for b2:
b2 --with-test link=shared define=BOOST_TEST_NO_MAIN
When the library is compiled with BOOST_TEST_NO_MAIN
defined, one source file must provide a definition for main.
The simplest is to delegate to unit_test_main
and provide an implementation of an initialization function that manually
adds test cases and suites to the test tree. Any test cases or test suites
added with BOOST_AUTO_TEST_CASE,
BOOST_FIXTURE_TEST_CASE,
BOOST_AUTO_TEST_SUITE
or BOOST_FIXTURE_TEST_SUITE
are automatically added.
// In exactly one source file #define BOOST_TEST_NO_MAIN #include <boost/test/unit_test.hpp> bool init_function() { // create test cases and suites and return a boolean indicating // success (true) or failure (false). return true; } int main(int argc, char* argv[]) { return ::boost::unit_test::unit_test_main(&init_function, argc, argv); }
main:
main:
![]() |
Home | Libraries | People | FAQ | More |
To build Boost.Test as a static library, first build the boost build tools,
as described in the Getting
Started documentation. After you have bootstrapped the build tools,
build the test library with by invoking b2 with arguments
similar to the following:
b2 --with-test link=static
This will place the resulting libraries in stage/lib
at the top level of the boost tree.
In a static library configuration, Boost.Test is compiled into a single
static library named boost_unit_test_framework and the
test executable is linked against that library. Exactly one compilation
unit in the test executable should define BOOST_TEST_MAIN,
in order run the tests.
// In exactly one source file #define BOOST_TEST_MAIN #include <boost/test/unit_test.hpp> // test cases (optional)
Additional source files simply include the main unit test header and define more test cases and/or suites.
// In additional source files #include <boost/test/unit_test.hpp> // test cases
To compile the library with no implementation of main,
add BOOST_TEST_NO_MAIN
to the cxxflags property for b2:
b2 --with-test link=static define=BOOST_TEST_NO_MAIN
When the library is compiled with BOOST_TEST_NO_MAIN
defined, one source file must provide a definition for main.
The simplest is to delegate to unit_test_main
and provide an implementation of an initialization function that manually
adds test cases and suites to the test tree. Any test cases or test suites
added with BOOST_AUTO_TEST_CASE,
BOOST_FIXTURE_TEST_CASE,
BOOST_AUTO_TEST_SUITE
or BOOST_FIXTURE_TEST_SUITE
are automatically added.
// In exactly one source file #define BOOST_TEST_NO_MAIN #include <boost/test/unit_test.hpp> boost::unit_test::test_suite *init_function(int argc, char *argv[]) { // create test cases and suites and return a pointer to any enclosing // suite, or 0. return 0; } int main(int argc, char *argv[]) { return boost::unit_test::unit_test_main(init_function, argc, argv); }
main:
main:
![]() |
Home | Libraries | People | FAQ | More |
Boost.Test is available in several forms:
The minimal header can be useful in situations where you don't already have the library built and want to quickly explore a test with a minimal amount of fuss. Once you need to create multiple unit tests, you will quickly outgrow the minimal header.
The header only form is useful when you don't want to be bothered with compiling the library. Once you have multiple compilation units with unit tests in each compilation unit, you will grow tired of the compilation cost involved with the header only form of the framework.
The static library form is the easiest to integrate into your build system as it doesn't require any installation of runtime files in order to execute your tests. This runtime simplicity comes at the cost of increased link times and executable sizes.
The dynamic library form requires the most effort for successful test execution, but provides faster link times than the static library, faster compile times than the header only form and provides all the features of the framework compared to the minimal header.
![]() |
Caution |
|---|---|
Boost.Test is not a thread-safe library. Care should be taken when automated tests create multiple threads and interact with data structures passed to Boost.Test macros or functions. |
![]() |
Home | Libraries | People | FAQ | More |
Boost.Test provides support for a special kind of test called an exception safety test.
![]() |
Home | Libraries | People | FAQ | More |
You may have an existing body of tests that you wish to register with Boost.Test
manually. You can use BOOST_TEST_CASE
to register a function taking no arguments and returning void
as a test case:
static void inserts_text() { std::ostringstream dest; hello_world(dest); BOOST_REQUIRE_EQUAL("Hello, world!\n", dest.str()); } static void register_function(test_suite& suite) { suite.add(BOOST_TEST_CASE(inserts_text)); }
You can use a test case method on a fixture class by registering a function that creates an instance of the fixture and invokes the test method. This assures that a fresh fixture is created for each test case, ensuring that each test executes independently of other tests.
class hello_fixture { public: void stream_with_badbit_throws_runtime_error() { dest.clear(std::ios_base::badbit); BOOST_REQUIRE_THROW(hello_world(dest), std::runtime_error); } std::ostringstream dest; };
static void stream_with_badbit_throws_runtime_error() { hello_fixture().stream_with_badbit_throws_runtime_error(); }; static void register_method_function_instance(test_suite& suite) { suite.add(BOOST_TEST_CASE(stream_with_badbit_throws_runtime_error)); }
You can register a method on a class as a test case by using Boost.Bind to bind the method to a static instance of the class. This can cause oen test case to influence the execution of another test case because they share the static fixture.
static hello_fixture hf; static void register_method_static_instance(test_suite& suite) { suite.add(BOOST_TEST_CASE( boost::bind(&hello_fixture::stream_with_badbit_throws_runtime_error, &hf))); }
A static instance of the class is used so that the instance exists at the time the test case is invoked. Test case invocation happens after registration, so using a local instance in the registration function is insufficient.
A new test suite is created with the BOOST_TEST_SUITE
macro. The new suite must be added to the master test suite to execute its
tests. Any number of test suites can be added in a hierarchy of suites and
any test case can be added to any test suite.
static test_suite* init_unit_test_suite(int argc, char* argv[]) { test_suite* hello_suite = BOOST_TEST_SUITE("hello"); register_function(*hello_suite); register_method_static_instance(*hello_suite); register_method_function_instance(*hello_suite); framework::master_test_suite().add(hello_suite); return 0; }
![]() |
Home | Libraries | People | FAQ | More |
In testing file I/O, we
showed an example of creating a class fake_directory_scanner
that acted as a simple test double for an interface. Such simple fake objects
are fine at first, but they're full of boring boiler plate code and after
a while it becomes tedious to write them by hand.
For collaborators defined by a pure virtual base class, also known as an interface, there are mock object frameworks that alleviate the need to write the repetitive boiler plate code. One such mock object framework that is designed to work with Boost.Test is the Turtle mock object framework.
Here is an example of the file system tests written using turtle:
#include "directory_scanner.hpp" #include <turtle/mock.hpp> MOCK_BASE_CLASS(mock_directory_scanner, directory_scanner) { MOCK_METHOD(begin, 1); MOCK_METHOD(has_next, 0); MOCK_METHOD(next, 0); };
Defining the mock object is considerably simpler than writing a fake object by hand. Turtle uses variadic argument macros and template based type deduction to infer the type signature of the methods simply from the number of arguments each method takes. This alleviates us from having to repeat all of this information from the interface into the implementation of the test double.
Now we can rewrite our tests to use a mock object configured for each test case:
static std::string const ARBITRARY_DIRECTORY_NAME("foo"); static std::string const ARBITRARY_NON_TEXT_FILE_NAME("foo.foo"); static std::string const ARBITRARY_TEXT_FILE_NAME("foo.txt"); static std::string const ARBITRARY_OTHER_TEXT_FILE_NAME("bar.txt"); struct text_files_fixture { text_files_fixture() { MOCK_EXPECT(scanner.begin).once().with(ARBITRARY_DIRECTORY_NAME); } void expect_enumerate_non_text_file() { MOCK_EXPECT(scanner.has_next).once().returns(true); MOCK_EXPECT(scanner.next).once().returns(ARBITRARY_NON_TEXT_FILE_NAME); } void expect_enumerate_text_file(std::string const& file_name = ARBITRARY_TEXT_FILE_NAME) { MOCK_EXPECT(scanner.has_next).once().returns(true); MOCK_EXPECT(scanner.next).once().returns(file_name); expected.push_back(file_name); } void expect_enumerate_end() { MOCK_EXPECT(scanner.has_next).once().returns(false); } mock_directory_scanner scanner; std::vector<std::string> empty; std::vector<std::string> expected; }; BOOST_FIXTURE_TEST_SUITE(test_text_files, text_files_fixture); BOOST_AUTO_TEST_CASE(returns_empty_for_empty_directory) { expect_enumerate_end(); std::vector<std::string> files = text_files(ARBITRARY_DIRECTORY_NAME, scanner); BOOST_REQUIRE_EQUAL_COLLECTIONS(empty.begin(), empty.end(), files.begin(), files.end()); } BOOST_AUTO_TEST_CASE(returns_empty_for_no_text_files) { expect_enumerate_non_text_file(); expect_enumerate_end(); std::vector<std::string> files = text_files(ARBITRARY_DIRECTORY_NAME, scanner); BOOST_REQUIRE_EQUAL_COLLECTIONS(empty.begin(), empty.end(), files.begin(), files.end()); } BOOST_AUTO_TEST_CASE(returns_file_for_text_file) { expect_enumerate_text_file(); expect_enumerate_end(); std::vector<std::string> files = text_files(ARBITRARY_DIRECTORY_NAME, scanner); BOOST_REQUIRE_EQUAL_COLLECTIONS(expected.begin(), expected.end(), files.begin(), files.end()); } BOOST_AUTO_TEST_CASE(returns_only_text_file_for_mixed_files) { expect_enumerate_text_file(); expect_enumerate_non_text_file(); expect_enumerate_end(); std::vector<std::string> files = text_files(ARBITRARY_DIRECTORY_NAME, scanner); BOOST_REQUIRE_EQUAL_COLLECTIONS(expected.begin(), expected.end(), files.begin(), files.end()); } BOOST_AUTO_TEST_CASE(returns_all_text_files) { expect_enumerate_text_file(); expect_enumerate_non_text_file(); expect_enumerate_text_file(ARBITRARY_OTHER_TEXT_FILE_NAME); expect_enumerate_end(); std::vector<std::string> files = text_files(ARBITRARY_DIRECTORY_NAME, scanner); BOOST_REQUIRE_EQUAL_COLLECTIONS(expected.begin(), expected.end(), files.begin(), files.end()); } BOOST_AUTO_TEST_SUITE_END();
The tests themselves are largely unchanged and what is different is the intention
revealing methods we placed in the test fixture. Mock object frameworks generally
provide a rich set of methods on the mock object for setting the expectations
on the number of times a method is called, such as once(),
the expected arguments to a method, such as with(), and
the return value of a method, such as returns().
With a turtle mock, the expectations are verified when the mock object is destroyed. The mock is a member in our fixture and will be destroyed at the end of every test case.
![]() |
Home | Libraries | People | FAQ | More |
xUnit Patterns[2], by Gerard Meszaros, presents several high level objectives for automated tests and individual goals for achieving those objectives:
In this section, we will discuss how the facilities in Boost.Test can support these goals; see xUnit Patterns for the description and rationale of these goals.
Tests can serve as specifications for the system under test if we write the test for the system first, using test-driven development. We imagine the perfect system that does exactly what we need and write a test as if that system existed. In order to achieve a failing test, we write just enough of the implementation to make the test compile.
A good way to ensure that the implementation causes a test failure is for called methods and functions to throw an exception indicating that the method or function called is not implemented:
#include <stdexcept> void free_function() { throw std::runtime_error("free_function not implemented."); }
We get a failing test right away, while still satisfying just enough syntax to satisfy the compiler.
It is well known that the longer a bug remains undetected in a software, the more expensive it is to fix.[3] If we are practicing test-driven development, then we find bugs in our implementation as soon as we code them. The time to find a bug in this manner can be as little as seconds and was demonstrated in the tutorial "Hello, Test!".
The easiest way to achieve this rapid feedback is to run the tests as part of the build. The details vary depending on your build system.
In Visual Studio 2012, this is most readily achieved by setting a post-build
build event as shown below. Because $(TargetPath) may
contain spaces, the variable is surrounded by double quotes to ensure that
the entire path to the executable is found. The description is given generically
using $(TargetName) so that this build event can be copied
to any test project's properties and be used without modification. Take care
that you define the build event for all configurations and all platforms
used by your build system so that the unit tests always run.
If you are using a Makefile to compile your code, create
a phony target that depends on your unit test executable and specify the
command to execute your unit test and create the phony target if the test
passes. This will ensure that the unit tests continue to run as long as they
fail because the phony target will only be updated when the tests pass.
If you are using Boost.Build and Jamfiles to compile your code, you can use
the rules in the testing module to incorporate your unit
tests into your build. The unit-test rule will build an
executable and run it, failing the build when the executable returns a non-zero
exit status. Other rules in the testing module may also
be useful.
If we keep our test cases focused on only a single behavior in our system
under test, then there is only a single cause for any particular unit test
to fail. We saw this in "Testing
With Exceptions" when we added a new test case to hello_world
for a bad stream. By choosing intention
revealing names for our test cases, we can identify the source of
the failure simply by reading the name of the failed test case.
Since each test case excercises only one scenario for the system under test, we must make at least one test case for each possible scenario. We can use the cyclomatic complexity as a rough proxy for the number of tests cases needed for any particular method or function to ensure that we have sufficient coverage of the system under test.
When confronted with a new software component or a new code base, how do we understand its behavior? We can read the documentation, but ultimately the behavior is defined by the code executed. Comments and documentation can lag the actual implementation. Sometimes, the only answer to our questions about a software component come from the implementation. If the component is only available to us in binary form, we don't have the luxury of consulting the source code in order to answer our questions.
Unit tests can serve as a form of executable documentation for software components. They tell us how the system responds to the scenarios orchestrated by the test cases.
When faced with a confusing aspect of a software component, we can answer questions about the behavior of the component by writing a unit test that describes our hypothesis about the component's behavior. If the unit test passes, we have verified our hypothesis. If the unit test fails, our hypothesis was incorrect; either way, we have learned something about the component. We can use unit tests to document subtle and unexpected behaviors of components. Unit tests are also the perfect documentation for a bug report on a component maintained by others.
When we start building a software system, we are able to keep all the details of the system in our mind because the system is small. As the size of the system increases, it becomes harder and harder to keep all the details of the system in mind as we make modifications. A comprehensive suite of unit tests over the system give us an automated regression test that gives us the confidence of knowing that our changes are not introducing any problems elsewhere in the code.
Automated tests should only reduce risk, not introduce risk into the system.
To achieve this, we want to keep all test code separated from production
code. The easiest way to do this is to put the system under test into a library
(static or shared) and link the test executable against the library. We saw
this in the tutorial "Hello,
Test!", when we separated the system under test into the hello
library and the test code into test_hello.cpp.
Boost.Test supports fully automated tests by allowing us to supply the inputs to the system under test in each test case in order to drive the system into the scenario of interest. Test cases should never rely on user input, or they will not be fully automated tests that can run unattended.
Boost.Test supports self-checking tests through its rich set of assertions. Each test case supplies the inputs to the system under test and validates the behavior of the system using assertions. Self-checking tests report only bad news and good news results in no notifications. The default output from the test runner only reports failing tests and a summary of all tests executed. The test runner also returns a non-zero status code when a test fails, allowing easy failure of continuous integration builds.
We should get the same results from automated tests every time we run them, provided the implementation of the system under test has not changed between runs. In the context of unit testing, this implies that a test case must control all the collaborators that can influence the system.
The most troublesome collaborators are among the following: * current date and time * device input * file system * system services (Windows registry, networking, etc.) * C style apis
In the book "Working Effectively with Legacy Code", Michael Feathers described a number of techniques for decoupling the system under test from such troublesome collaborators that can cause unit tests to spuriously fail. All the techniques are variations on a theme: introduce a level of indirection to decouple the system under test from a collaborator. C++ offers static polymorphism via templates as well as the usual dynamic polymorphism via interfaces to decouple a system under test from a collaborator.
We keep tests simple by exercising only one scenario for each test case. Simple test cases read linearly through the phases of setup, exercise and verify. Trying to exercise too much functionality in a single test case can introduce unnecessary complexity into the test.
Duplication between test cases can make tests hard to read by distracting us from the steady rhythm of setup, exercise and verify of test cases. You may find it useful to apply the rule of three when writing test cases to decide when to extract duplication into a fixture.
Sometimes low-level setup details get in the way of a test reading clearly. This could be the result of a complicated data structure needed in order to exercise the system down a particular code path. Similarly, the verification of a result produced by the system under test may involve a series of assertions that make the test hard to follow. Boost.Test provides fixtures as a way to localize these distracting details by extracting setup and assertion methods into the fixture.
Over time we build up a series of methods in the fixture that allow us to express domain concepts succinctly and clearly in the tests, making them more expressive of the scenario in the domain. Fixtures can be combined through aggregation or inheritance in order to express combinations and hierarchies of domain concepts.
We keep test code separated from production code with the packaging mechanisms provided by C++. Production code is supplied to the test executable as a library, either static or dynamic. The test code resides in separate source files from the production code. The production code consumed by the test code is compiled with the exact same preprocessor settings as the production code to ensure that tests do not influence the production code.
We keep concerns separated in our tests by testing each concern in its own test case. Each test case exercises a single scenario and our tests exercise the responsibilities or classes individually. If we are practicing test-driven development, we keep the single responsibility principle in mind as we are creating the system to satisfy the evolving tests. When our tests start involving more than one concern, it can be a sign that our system under test is covering more than one responsibility.
Test cases are robust when small changes to the system under test result in a small number of test cases failing. If a small change to the system results in many test cases failing, then our tests are not robust. If our tests cases do not sufficiently isolate the system under test from its collaborators, then a change to one part of the system can cause tests on seemingly unrelated parts of the system to fail. If we have repeated assertions in many test cases for the same system under test, then many test cases can fail if that single assertion fails. Each of these situations is a case of overlap between test cases; in the first case, the overlap is between the parts of the production code unrelated to the system under test that we exercise and in the second case, the overlap is between test cases on the system under test.
[2] The term xUnit is a generic term for unit testing frameworks, such as jUnit. The advice in xUnit Patterns applies equally well to Boost.Test.
![]() |
Home | Libraries | People | FAQ | More |
If there is considerable logic in an appliation's main
function, this can be difficult to unit test. The One
Definition Rule prevents us from having the application's main
and the unit test executable's main in the same executable.
Furthermore, even if we could perform some trick to resolve the multiply
defined symbol[4], we would still need to figure out how to link the test executable
with the application's main function to test the code.
When it becomes difficult to test code where it is currently, such as in
the body of main, the simplest thing to do is to move
the code somewhere else that makes it easy to test. Here is one way to accomplish
this:
main to app_main.
app_main to a library.
main that calls app_main.
app_main by linking against the library.
The delegating main looks like this:
extern int app_main(int argc, char* argv[]); int main(int argc, char* argv[]) { return app_main(argc, argv); }
If you don't already have a library for app_main, then
create one and add all the other application code to the library as well.
The build logic for making the executable will consist of compiling a single
source file containing your delegating implementation of main
and linking against a library containing the rest of the application. This
will give you a starting point for writing unit tests for anything in your
application.
![]() |
Home | Libraries | People | FAQ | More |
A common problem encountered in unit testing is interaction with the file system: scanning directories, creating files, opening files, reading files, writing files, creating symbolic links and so-on. Interacting directly with the file system when executing unit tests can lead to a failure of tests to be robust or repeatable. We also want our unit tests to be fast; an execution time of 100 milliseconds is considered a slow unit test. Interacting directly with the file system can make our unit tests take too long to execute.
The simplest approach is to wrap file system operations in an interface and perform all operations through the interface. Consider the following example of a function that returns a vector of filenames ending in ".txt" in a given directory:
extern std::vector<std::string> text_files(std::string const& directory);
How can we unit test text_files without relying on the
actual contents of the file system? We can decouple text_files
from the file system by introducing an interface:
class directory_scanner; extern std::vector<std::string> text_files( std::string const& directory, directory_scanner& scanner);
We've used a forward declaration of directory_scanner
where text_files is declared. The interface looks like
this:
class directory_scanner { public: virtual ~directory_scanner() {} virtual void begin(std::string const &directory) = 0; virtual bool has_next() const = 0; virtual std::string next() const = 0; };
The interface directory_scanner is used to isolate the
free function text_files from directly interacting with
the file system. In the unit tests, we use an implementation of directory_scanner
that senses how text_files uses the interface and allows
us to control the data made available to text_files. The
tests can use a hand-crafted fake implementation or an implementation from
a mock library. The fake might look something like this:
class fake_directory_scanner : public directory_scanner { public: fake_directory_scanner() : begin_called(false), has_next_called(false), next_called(false), next_call_count(0U) {} virtual ~fake_directory_scanner() {} virtual void begin(std::string const &directory) { begin_called = true; begin_last_directory = directory; } bool begin_called; std::string begin_last_directory; virtual bool has_next() const { has_next_called = true; return next_call_count <= next_fake_results.size(); } mutable bool has_next_called; bool has_next_fake_result; virtual std::string next() const { next_called = true; ++next_call_count; return has_next() ? next_fake_results[next_call_count - 1U] : ""; } mutable bool next_called; mutable std::size_t next_call_count; std::vector<std::string> next_fake_results; };
The tests for text_files use the fake_directory_scanner
to specify the configuration of the file system for the different test cases:
struct text_files_fixture { fake_directory_scanner scanner; }; BOOST_FIXTURE_TEST_SUITE(test_text_files, text_files_fixture); BOOST_AUTO_TEST_CASE(returns_empty_for_empty_directory) { std::vector<std::string> empty; std::vector<std::string> files = text_files("foo", scanner); BOOST_REQUIRE_EQUAL_COLLECTIONS(empty.begin(), empty.end(), files.begin(), files.end()); } BOOST_AUTO_TEST_CASE(returns_empty_for_no_text_files) { scanner.next_fake_results.push_back("foo.foo"); std::vector<std::string> empty; std::vector<std::string> files = text_files("foo", scanner); BOOST_REQUIRE_EQUAL_COLLECTIONS(empty.begin(), empty.end(), files.begin(), files.end()); } BOOST_AUTO_TEST_CASE(returns_file_for_text_file) { scanner.next_fake_results.push_back("foo.txt"); std::vector<std::string> expected; expected.push_back("foo.txt"); std::vector<std::string> files = text_files("foo", scanner); BOOST_REQUIRE_EQUAL_COLLECTIONS(expected.begin(), expected.end(), files.begin(), files.end()); } BOOST_AUTO_TEST_CASE(returns_only_text_file_for_mixed_files) { scanner.next_fake_results.push_back("foo.txt"); scanner.next_fake_results.push_back("foo.foo"); std::vector<std::string> expected; expected.push_back("foo.txt"); std::vector<std::string> files = text_files("foo", scanner); BOOST_REQUIRE_EQUAL_COLLECTIONS(expected.begin(), expected.end(), files.begin(), files.end()); } BOOST_AUTO_TEST_SUITE_END();
In production code, we use an implementation of directory_scanner
that interacts directly with the file system using Boost.FileSystem.
class filesystem_directory_scanner : public directory_scanner { public: filesystem_directory_scanner() {} virtual ~filesystem_directory_scanner() {} virtual void begin(std::string const &directory) { current = boost::filesystem::directory_iterator(directory); } virtual bool has_next() const { return current != end; } virtual std::string next() const { if (has_next()) { std::string const result = (*current).path().filename().string(); do { ++current; } while (has_next() && !boost::filesystem::is_regular_file((*current).path())); return result; } throw std::runtime_error("no next path"); } private: mutable boost::filesystem::directory_iterator current; boost::filesystem::directory_iterator end; };
We've wrapped just enough of Boost.FileSystem for our needs; Boost.FileSystem
has a very large surface area and we don't need to put an interface around
the entire thing, just enough to satisfy the needs of text_files.
If we don't want production code to have to worry about supplying an instance
of filesystem_directory_scanner to text_files,
we can use overloading on text_files and use simple delegation
to supply the dependency:
extern std::vector<std::string> text_files(std::string const& directory) { filesystem_directory_scanner scanner; return text_files(directory, scanner); }
Seeing this, you might wonder if we need to unit test the overload we just
created? Because we are using simple delegation here, there isn't sufficient
complexity to warrant unit testing. However, we have no unit tests for filesystem_directory_scanner,
which does have control structures. We will want some sort of automated tests
around this code to verify that it functions properly. We can use acceptance
tests to verify the system as a whole, exercising all the components
end-to-end and not just in isolation.
![]() |
Home | Libraries | People | FAQ | More |
A common problem encountered in unit testing is interaction with the file system: scanning directories, creating files, opening files, reading files, writing files, creating symbolic links and so-on. Interacting directly with the file system when executing unit tests can lead to a failure of tests to be robust or repeatable. We also want our unit tests to be fast; an execution time of 100 milliseconds is considered a slow unit test. Interacting directly with the file system can make our unit tests take too long to execute.
The simplest approach is to wrap file system operations in an interface and perform all operations through the interface. Consider the following example of a function that returns a vector of filenames ending in ".txt" in a given directory:
extern std::vector<std::string> text_files(std::string const& directory);
How can we unit test text_files without relying on the
actual contents of the file system? We can decouple text_files
from the file system by introducing an interface:
class directory_scanner; extern std::vector<std::string> text_files( std::string const& directory, directory_scanner& scanner);
We've used a forward declaration of directory_scanner
where text_files is declared. The interface looks like
this:
class directory_scanner { public: virtual ~directory_scanner() {} virtual void begin(std::string const &directory) = 0; virtual bool has_next() const = 0; virtual std::string next() const = 0; };
The interface directory_scanner is used to isolate the
free function text_files from directly interacting with
the file system. In the unit tests, we use an implementation of directory_scanner
that senses how text_files uses the interface and allows
us to control the data made available to text_files. The
tests can use a hand-crafted fake implementation or an implementation from
a mock library. The fake might look something like this:
class fake_directory_scanner : public directory_scanner { public: fake_directory_scanner() : begin_called(false), has_next_called(false), next_called(false), next_call_count(0U) {} virtual ~fake_directory_scanner() {} virtual void begin(std::string const &directory) { begin_called = true; begin_last_directory = directory; } bool begin_called; std::string begin_last_directory; virtual bool has_next() const { has_next_called = true; return next_call_count <= next_fake_results.size(); } mutable bool has_next_called; bool has_next_fake_result; virtual std::string next() const { next_called = true; ++next_call_count; return has_next() ? next_fake_results[next_call_count - 1U] : ""; } mutable bool next_called; mutable std::size_t next_call_count; std::vector<std::string> next_fake_results; };
The tests for text_files use the fake_directory_scanner
to specify the configuration of the file system for the different test cases:
static std::string const ARBITRARY_DIRECTORY_NAME("foo"); static std::string const ARBITRARY_NON_TEXT_FILE_NAME("foo.foo"); static std::string const ARBITRARY_TEXT_FILE_NAME("foo.txt"); static std::string const ARBITRARY_OTHER_TEXT_FILE_NAME("bar.txt"); struct text_files_fixture { void expect_enumerate_non_text_file() { scanner.next_fake_results.push_back(ARBITRARY_NON_TEXT_FILE_NAME); } void expect_enumerate_text_file(std::string const& file_name = ARBITRARY_TEXT_FILE_NAME) { scanner.next_fake_results.push_back(file_name); expected.push_back(file_name); } fake_directory_scanner scanner; std::vector<std::string> empty; std::vector<std::string> expected; }; BOOST_FIXTURE_TEST_SUITE(test_text_files, text_files_fixture); BOOST_AUTO_TEST_CASE(returns_empty_for_empty_directory) { std::vector<std::string> files = text_files(ARBITRARY_DIRECTORY_NAME, scanner); BOOST_REQUIRE_EQUAL_COLLECTIONS(empty.begin(), empty.end(), files.begin(), files.end()); } BOOST_AUTO_TEST_CASE(returns_empty_for_no_text_files) { expect_enumerate_non_text_file(); std::vector<std::string> files = text_files(ARBITRARY_DIRECTORY_NAME, scanner); BOOST_REQUIRE_EQUAL_COLLECTIONS(empty.begin(), empty.end(), files.begin(), files.end()); } BOOST_AUTO_TEST_CASE(returns_file_for_text_file) { expect_enumerate_text_file(); std::vector<std::string> files = text_files(ARBITRARY_DIRECTORY_NAME, scanner); BOOST_REQUIRE_EQUAL_COLLECTIONS(expected.begin(), expected.end(), files.begin(), files.end()); } BOOST_AUTO_TEST_CASE(returns_only_text_file_for_mixed_files) { expect_enumerate_text_file(); expect_enumerate_non_text_file(); std::vector<std::string> files = text_files(ARBITRARY_DIRECTORY_NAME, scanner); BOOST_REQUIRE_EQUAL_COLLECTIONS(expected.begin(), expected.end(), files.begin(), files.end()); } BOOST_AUTO_TEST_CASE(returns_all_text_files) { expect_enumerate_text_file(); expect_enumerate_non_text_file(); expect_enumerate_text_file(ARBITRARY_OTHER_TEXT_FILE_NAME); std::vector<std::string> files = text_files(ARBITRARY_DIRECTORY_NAME, scanner); BOOST_REQUIRE_EQUAL_COLLECTIONS(expected.begin(), expected.end(), files.begin(), files.end()); } BOOST_AUTO_TEST_SUITE_END();
In production code, we use an implementation of directory_scanner
that interacts directly with the file system using Boost.FileSystem.
class filesystem_directory_scanner : public directory_scanner { public: filesystem_directory_scanner() {} virtual ~filesystem_directory_scanner() {} virtual void begin(std::string const &directory) { current = boost::filesystem::directory_iterator(directory); } virtual bool has_next() const { return current != end; } virtual std::string next() const { if (has_next()) { std::string const result = (*current).path().filename().string(); do { ++current; } while (has_next() && !boost::filesystem::is_regular_file((*current).path())); return result; } throw std::runtime_error("no next path"); } private: mutable boost::filesystem::directory_iterator current; boost::filesystem::directory_iterator end; };
We've wrapped just enough of Boost.FileSystem for our needs; Boost.FileSystem
has a very large surface area and we don't need to put an interface around
the entire thing, just enough to satisfy the needs of text_files.
If we don't want production code to have to worry about supplying an instance
of filesystem_directory_scanner to text_files,
we can use overloading on text_files and use simple delegation
to supply the dependency:
extern std::vector<std::string> text_files(std::string const& directory) { filesystem_directory_scanner scanner; return text_files(directory, scanner); }
Seeing this, you might wonder if we need to unit test the overload we just
created? Because we are using simple delegation here, there isn't sufficient
complexity to warrant unit testing. However, we have no unit tests for filesystem_directory_scanner,
which does have control structures. We will want some sort of automated tests
around this code to verify that it functions properly. We can use acceptance
tests to verify the system as a whole, exercising all the components
end-to-end and not just in isolation.
![]() |
Home | Libraries | People | FAQ | More |
When testing a large class, you may find yourself wanting to test protected or private members of the class. The best approach is to test those members by testing the public members of the class. If using the public members of a class requires considerable setup in order to force execution down a particular path that exercises the protected or private member in question, then you may wish to refactor the code to enhance testability.
The most expedient technique for protected members is to raise their visibility
through derivation. Suppose we have a base class B
with a protected member p
that we wish to test:
class B { // ... other stuff in B protected: bool p(); };
We can derive a class D in
the test code from the class B
in the production code that raises the visibility of p:
class D : public B { // ... other stuff needed to build a D from a B public: using B::p; };
Now we can write a test for D::p.
While this certainly seems expedient, it's annoying to write these derived
classes simply for the purposes of hoisting members into public visibility.
It also just feels dirty. We're taking implementation details that are supposed
to be hidden from consumers of the class and we're exposing them. If we are
not diligent and watchful, this class D
in the test project that was only intended for testing may find itself showing
up in the production code.
Maybe the problem isn't one of visibility but that we simply aren't listening closely enough to the code in the first place. As Herb Sutter shows us in Uses and Abuses of Access Rights, the "Liar", the "Pickpocket", the "Cheat" and the "Language Lawyer" can all find ways to subvert the access protections afforded to a class.
When we are tempted to test non-public methods of a class, it's because we feel that there is sufficient complexity in these non-public methods to warrant testing them. What if that complexity is trying to tell us something? If our class is so complex, isn't it possible that it's violating the Single Responsibility Principle? Maybe the class is trying to encompass several responsibilities and should be decomposed into two or more classes, each with a single responsibility. We could perform the Extract Class refactoring to create two classes with appropriate public interfaces and then write tests against those new public interfaces.
Another choice is to refactor the original class using the "pimpl idiom", elevate the visibility to public of all the methods on the implementation class and write tests against the implementation class. This has the same downsides as the derive-and-elevate approach and we're still ignoring the whispers of the code.
When your code is hard to test, your code is telling you something. Listen to the code!
![]() |
Home | Libraries | People | FAQ | More |
![]() |
Home | Libraries | People | FAQ | More |
This documentation provides material for both new users and advanced users. If you are completely new to automated testing, you may wish to read Wikipedia's article on test-driven development and consult the online book xUnit Test Patterns. The amount of information available on automated testing has exploded in the past decade and these are only some suggested starting points and not intended to be an exhaustive list.
To get started quickly writing your first test, read the tutorial sections. For advice on designing and maintaining your tests, read the section on test case design. For advanced uses of the library, consult the reference.
![]() |
Home | Libraries | People | FAQ | More |
Automated tests are an important part of verifying software. At the developer level, automated tests provide confidence that changes made to the software do not result in new defects. At the customer level, automated tests provide confidence that new features meet expectations and existing features continue to function unchanged.
Boost.Test is a library that supports the automated testing of software, primarily aimed at satisfying the needs of the developer.
![]() |
Home | Libraries | People | FAQ | More |
BITWISE_level_EQUAL(lhs,
rhs) compares the two arguments
for bitwise equality and fails if they are not equal. This can be useful
when testing integral values that represent a logical or combination of
bit flags.
enum bit_flags { source_file = 1u, header_file = 2u, build_file = 4u }; BOOST_AUTO_TEST_CASE(example_bitwise_equal) { BOOST_REQUIRE_BITWISE_EQUAL( source_file | build_file, build_file | source_file); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_CLOSE(lhs,
rhs, tolerance)
compares the two floating-point arguments and considers them equal if they
agree within the given tolerance. The tolerance
is given as a percentage.
BOOST_AUTO_TEST_CASE(example_close) { BOOST_REQUIRE_CLOSE(100.f, 100.9f, 1.f); BOOST_REQUIRE_CLOSE(100.f, 99.1f, 1.f); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_CLOSE_FRACTION(lhs,
rhs, tolerance)
compares the two floating-point arguments and considers them equal if they
agree within the given tolerance. The tolerance
is given as a percentage.
BOOST_AUTO_TEST_CASE(example_close_fraction) { BOOST_REQUIRE_CLOSE_FRACTION(100.f, 100.9f, 1.f); BOOST_REQUIRE_CLOSE_FRACTION(100.f, 99.1f, 1.f); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_EQUAL_COLLECTIONS(lhs_begin,
lhs_end, rhs_begin,
rhs_end) compares two collections
for equality. Two collections are considered equal if they have the same
number of elements and the elements compare equal by operator==. The elements are obtained through the
supplied iterators on the collections. The diagnostic message is constructed
from applying operator<<
to each of the elements in the collections.
![]() |
Important |
|---|---|
If you get a strange compile error when using |
static std::list<int> generate_list() { std::list<int> l; l.push_front(3); l.push_front(2); l.push_front(1); return l; } BOOST_AUTO_TEST_CASE(example_equal_collections) { std::vector<int> expected; expected.push_back(1); expected.push_back(2); expected.push_back(3); std::list<int> actual = generate_list(); BOOST_REQUIRE_EQUAL_COLLECTIONS( expected.begin(), expected.end(), actual.begin(), actual.end()); } BOOST_AUTO_TEST_CASE(example_equal_collections_pod) { int const expected[] = { 1, 2, 3 }; std::list<int> actual = generate_list(); BOOST_REQUIRE_EQUAL_COLLECTIONS( &expected[0], &expected[sizeof(expected)/sizeof(expected[0])], actual.begin(), actual.end()); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_EXCEPTION(statement,
exception, predicate)
asserts that when statement throws an exception
of type exception, the predicate
applied to the instance of the exception returns true.
This is used to verify not only that an exception of the correct type was
thrown, but that the contents of the thrown exception meet the expectations
of the predicate.
class error_number_exception { public: error_number_exception(int num) : num_(num) { } int error_number() const { return num_; } private: int num_; }; static bool has_error_number_1(error_number_exception const& ex) { return ex.error_number() == 1; } BOOST_AUTO_TEST_CASE(example_exception) { BOOST_REQUIRE_EXCEPTION(throw error_number_exception(1), error_number_exception, has_error_number_1); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_GE(lhs,
rhs) asserts that lhs
is greater than or equal to rhs. The comparison
is made by applying operator>= to both arguments. The diagnostic
message is constructed from applying operator<< to the two arguments.
![]() |
Important |
|---|---|
If you get a strange compile error when using |
BOOST_AUTO_TEST_CASE(example_ge) { // integral types unsigned const u = 1u; int const i = -10; char const A = 'A'; // standard library types providing operator>= and operator<< std::string const s = "scooby"; BOOST_REQUIRE_GE(2u, u); BOOST_REQUIRE_GE(1u, u); BOOST_REQUIRE_GE(-9, i); BOOST_REQUIRE_GE(-10, i); BOOST_REQUIRE_GE('B', A); BOOST_REQUIRE_GE('A', A); BOOST_REQUIRE_GE("scoobz", s); BOOST_REQUIRE_GE("scooby", s); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_GT(lhs,
rhs) asserts that lhs
is greater than rhs. The comparison is made
by applying operator>
to both arguments. The diagnostic message is constructed from applying
operator<<
to the two arguments.
![]() |
Important |
|---|---|
If you get a strange compile error when using |
BOOST_AUTO_TEST_CASE(example_gt) { // integral types unsigned const u = 1u; int const i = -10; char const A = 'A'; // standard library types providing operator> and operator== std::string const s = "scooby"; BOOST_REQUIRE_GT(2u, u); BOOST_REQUIRE_GT(-9, i); BOOST_REQUIRE_GT('B', A); BOOST_REQUIRE_GT("scoobz", s); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_LE(lhs,
rhs) asserts that lhs
is less than or equal to rhs. The comparison
is made by applying operator<= to both arguments. The diagnostic
message is constructed from applying operator<< to the two arguments.
![]() |
Important |
|---|---|
If you get a strange compile error when using |
BOOST_AUTO_TEST_CASE(example_le) { // integral types unsigned const u = 10u; int const i = -10; char const M = 'M'; // standard library types providing operator>= and operator<< std::string const s = "scooby"; BOOST_REQUIRE_LE(9u, u); BOOST_REQUIRE_LE(10u, u); BOOST_REQUIRE_LE(-11, i); BOOST_REQUIRE_LE(-10, i); BOOST_REQUIRE_LE('L', M); BOOST_REQUIRE_LE('M', M); BOOST_REQUIRE_LE("scoobx", s); BOOST_REQUIRE_LE("scooby", s); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_LT(lhs,
rhs) asserts that lhs
is less than rhs. The comparison is made by
applying operator<
to both arguments. The diagnostic message is constructed from applying
operator<<
to the two arguments.
![]() |
Important |
|---|---|
If you get a strange compile error when using |
BOOST_AUTO_TEST_CASE(example_lt) { // integral types unsigned const u = 10u; int const i = -10; char const M = 'M'; // standard library types providing operator>= and operator<< std::string const s = "scooby"; BOOST_REQUIRE_LT(9u, u); BOOST_REQUIRE_LT(-11, i); BOOST_REQUIRE_LT('L', M); BOOST_REQUIRE_LT("scoobx", s); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_MESSAGE(predicate,
message) emits message
if the supplied predicate evaluates to false.
The message is applied to an output stream with
operator<<
and the argument can contain additional applications of operator<< for building up complex messages.
The predicate can return bool or predicate_result.
static int g_i; // simple predicate static bool global_int_is_positive() { return g_i > 0; } // predicate that builds up detail message static boost::test_tools::predicate_result global_int_equal(int expected) { if (g_i == expected) { return true; } boost::test_tools::predicate_result failed = false; failed.message() << "g_i != " << expected << "; actual: " << g_i; return failed; } BOOST_AUTO_TEST_CASE(example_message) { g_i = 1; BOOST_REQUIRE_MESSAGE(global_int_is_positive(), "g_i is not positive; actual: " << g_i); BOOST_REQUIRE_MESSAGE(global_int_equal(1), ""); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_NE(lhs,
rhs) asserts that lhs
is not equal to rhs. The comparison is made
by applying operator!=
to both arguments. The diagnostic message is constructed from applying
operator<<
to the two arguments.
![]() |
Important |
|---|---|
If you get a strange compile error when using |
BOOST_AUTO_TEST_CASE(example_ne) { // integral types unsigned const u = 1u; int const i = -1; char const A = 'A'; // standard library types providing operator!= and operator<< std::string const s = "scooby"; BOOST_REQUIRE_NE(2u, u); BOOST_REQUIRE_NE(-2, i); BOOST_REQUIRE_NE('B', A); BOOST_REQUIRE_NE("scoobz", s); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_NO_THROW(statement)
asserts that statement does not throw an exception.
BOOST_AUTO_TEST_CASE(example_no_throw) { BOOST_REQUIRE_NO_THROW(1 + 1); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_PREDICATE(predicate,
args) asserts that the supplied
predicate applied to args
evaluates to true. The supplied predicate must
have a return type of bool and argument types that are
compatible with the argument list args. Because
BOOST_level_PREDICATE
is a macro, the args must be supplied as a sequence
of parenthesized values, with no comma separating the values.
static bool custom_string_compare(char const* const expected, char const* const actual) { return std::strcmp(expected, actual) == 0; } BOOST_AUTO_TEST_CASE(example_predicate) { char const* const s = "scooby"; BOOST_REQUIRE_PREDICATE(custom_string_compare, ("scooby")(s)); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_SMALL(value,
tolerance) checks that the
value is within tolerance
of zero.
BOOST_AUTO_TEST_CASE(example_small) { float const f = 0.1f; BOOST_REQUIRE_SMALL(f, 0.25f); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_TEST_DONT_PRINT_LOG_VALUE(type)
instructs the test framework to ignore values of type type
when constructing diagnostic messages. It does this by defining an empty
implementation of a print function specialized for type.
Because the specialization is inside an implementation namespace for Boost.Test,
the macro must be invoked at the global namespace scope. Therefore, it
cannot be used inside a test suite or any other namespace.
struct custom { int value; }; BOOST_TEST_DONT_PRINT_LOG_VALUE(custom); static bool operator==(custom const& expected, custom const& actual) { return expected.value == actual.value; } BOOST_AUTO_TEST_CASE(example_test_dont_print_log_value) { custom const v1 = { 1 }; custom const v2 = { 1 }; BOOST_REQUIRE_EQUAL(v1, v2); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_TEST_ERROR(message)
always fails and emits the given message at
the CHECK assertion level.
![]() |
Home | Libraries | People | FAQ | More |
BOOST_TEST_IS_DEFINED(symbol)
asserts that symbol is a defined value.
![]() |
Home | Libraries | People | FAQ | More |
BOOST_FAIL(message)
always fails and emits the given message at
the REQUIRE assertion level. Other assertion macros
are generally preferred over BOOST_FAIL because they
emit better diagnostics in the case of failure.
There are two situations where you might be tempted to use BOOST_FAIL:
testing the situations where the system under test will throw exceptions
or comparing against the values computed by the system under test. For
testing exception generation, use BOOST_REQUIRE_THROW,
BOOST_REQUIRE_NO_THROW
or BOOST_REQUIRE_EXCEPTION.
For testing against values computed by the system under test, use the comparing
assertions.
BOOST_AUTO_TEST_CASE(example_fail) { BOOST_FAIL("This should never happen."); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_EQUAL(lhs, rhs)
compares the two arguments with operator==. The diagnostic message is constructed
with operator<<
on the two arguments.
![]() |
Important |
|---|---|
If you get a strange compile error when using |
BOOST_AUTO_TEST_CASE(example_equal) { // integral types unsigned const u = 1u; int const i = -1; char const A = 'A'; // standard library types providing operator== and operator<< std::string const s = "scooby"; BOOST_REQUIRE_EQUAL(1u, u); BOOST_REQUIRE_EQUAL(-1, i); BOOST_REQUIRE_EQUAL('A', A); BOOST_REQUIRE_EQUAL("scooby", s); }
// custom data structure struct symbol { char const* const name; int value; }; // custom comparison operator static bool operator==(symbol const& lhs, symbol const& rhs) { return lhs.value == rhs.value && std::string(lhs.name) == std::string(rhs.name); } // custom stream insertion operator static std::ostream& operator<<(std::ostream& stream, symbol const& value) { return stream << value.name << ": " << value.value; } BOOST_AUTO_TEST_CASE(example_equal_custom_compare) { symbol const s1 = { "var" , 1 }; symbol const s2 = { "var", 1 }; // If the compiler doesn't collapse multiple constants, then: // s1.name != s2.name; BOOST_REQUIRE_EQUAL(s1, s2); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_EXCEPTION(expression,
exception, predicate)
asserts that when expression throws an exception
of type exception, the predicate
applied to the instance of the exception returns true.
This is used to verify not only that an exception of the correct type was
thrown, but that the contents of the thrown exception meet the expectations
of the predicate.
The predicate can return bool,
or predicate_result
which allows the predicate to build up a detailed failure message.
class error_number_exception { public: error_number_exception(int num) : num_(num) { } int error_number() const { return num_; } private: int num_; }; static bool has_error_number_1(error_number_exception const& ex) { return ex.error_number() == 1; } BOOST_AUTO_TEST_CASE(example_exception) { BOOST_REQUIRE_EXCEPTION(throw error_number_exception(1), error_number_exception, has_error_number_1); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_MESSAGE(predicate,
message) emits message
if the supplied predicate evaluates to false.
The message is applied to an output stream with
operator<<
and the argument can contain additional applications of operator<< for building up complex messages.
The predicate can return bool or predicate_result.
static int g_i; // simple predicate static bool global_int_is_positive() { return g_i > 0; } // predicate that builds up detail message static boost::test_tools::predicate_result global_int_equal(int expected) { if (g_i == expected) { return true; } boost::test_tools::predicate_result failed = false; failed.message() << "g_i != " << expected << "; actual: " << g_i; return failed; } BOOST_AUTO_TEST_CASE(example_message) { g_i = 1; BOOST_REQUIRE_MESSAGE(global_int_is_positive(), "g_i is not positive; actual: " << g_i); BOOST_REQUIRE_MESSAGE(global_int_equal(1), "g_i equals 1"); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_NO_THROW(expression)
asserts that expression does not throw an exception.
BOOST_AUTO_TEST_CASE(example_no_throw) { BOOST_REQUIRE_NO_THROW(1 + 1); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_THROW(expression,
exception) asserts that
expression throws an exception of type exception
or a type derived from exception.
static void always_throws() { throw std::runtime_error("whoops"); } BOOST_AUTO_TEST_CASE(example_throw) { BOOST_REQUIRE_THROW(always_throws(), std::runtime_error); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_TEST_DONT_PRINT_LOG_VALUE(type)
instructs the test framework to ignore values of type type
when constructing diagnostic messages. It does this by defining an empty
implementation of a print function specialized for type.
Because the specialization is inside an implementation namespace for Boost.Test,
the macro must be invoked at the global namespace scope. Therefore, it
cannot be used inside a test suite or any other namespace.
struct custom { int value; }; BOOST_TEST_DONT_PRINT_LOG_VALUE(custom); static bool operator==(custom const& expected, custom const& actual) { return expected.value == actual.value; } BOOST_AUTO_TEST_CASE(example_test_dont_print_log_value) { custom const v1 = { 1 }; custom const v2 = { 1 }; BOOST_REQUIRE_EQUAL(v1, v2); }
![]() |
Home | Libraries | People | FAQ | More |
When using the library or header-only version of Boost.Test, many assertion macros are provided in three levels that determine the behavior when the assertion fails and how a failed assertion interacts with the test runner.
Table 1.2. Assertion Levels
|
Level |
Test Case Fails? |
Aborts Execution? |
|---|---|---|
|
|
No |
No |
|
|
Yes |
no |
|
|
Yes |
Yes |
The WARN level issues a diagnostic message, but the
test case is not considered to have failed and continues executing. The
CHECK level issues a message to the test log on failure,
marks the test case as failed and continues executing. The REQUIRE
level issues a message to the test log on failure, marks the test case
as failed and halts execution of the test case.
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_BITWISE_EQUALBOOST_level_CLOSEBOOST_level_CLOSE_FRACTIONBOOST_level_EQUALBOOST_level_EQUAL_COLLECTIONSBOOST_level_EXCEPTIONBOOST_FAILBOOST_level_GEBOOST_level_GTBOOST_level_LEBOOST_level_LTBOOST_level_MESSAGEBOOST_level_NEBOOST_level_NO_THROWBOOST_level_PREDICATEBOOST_level_SMALLBOOST_level_THROWBOOST_TEST_DONT_PRINT_LOG_VALUEAssertions are used to validate the result of exercising the system under test. When an assertion fails, a diagnostic message is created and the failed assertion is recorded. Different assertion levels allow you to control how a failed assertion is interpreted by the test runner.
![]() |
Important |
|---|---|
When an assertion involves a user-defined datatype, a stream insertion
operator ( |
The minimal header test framework does not provide the facilities described here.
![]() |
Home | Libraries | People | FAQ | More |
|
Macro |
Meaning |
|---|---|
|
When defined, the alternative |
|
|
When defined, the implementation is compiled as a shared library.
Defining |
|
|
When defined, an implementation of main is included in the source file. |
|
|
When defined, it provides the name of the master test suite, otherwise a default name is used. |
|
|
When defined, no automatic linking is performed. |
|
|
When defined, no implementation of main is provided in any configuration.
Static and shared libraries must have been built with this symbol
defined for it to take effect when using the library. The test
executable must provide its own implementation of |
When using any of these macros, they must be defined before including any header from Boost.Test.
![]() |
Home | Libraries | People | FAQ | More |
#include <boost/test/debug.hpp>
namespace boost { namespace test { bool under_debugger(); void debugger_break(); struct dbg_startup_info { long pid; bool break_or_continue; unit_test::const_string binary_path; unit_test::const_string display; unit_test::const_string init_done_lock; }; typedef boost::function<void (dbg_startup_info const&)> dbg_starter; std::string set_debugger( unit_test::const_string dbg_id, dbg_starter s = dbg_starter() ); bool attach_debugger( bool break_or_continue = true ); void detect_memory_leaks( bool on_off, unit_test::const_string report_file = unit_test::const_string() ); void break_memory_alloc( long mem_alloc_order_num ); }} // boost::test
#include <boost/test/debug_config.hpp
BOOST_TEST_DBG_LIST BOOST_TEST_STAT_LINE_MAX
#include <boost/test/execution_monitor.hpp>
namespace boost { class execution_exception { typedef boost::unit_test::const_string const_string; public: enum error_code { no_error = 0, user_error = 200, cpp_exception_error = 205, system_error = 210, timeout_error = 215, user_fatal_error = 220, system_fatal_error = 225 }; struct BOOST_TEST_DECL location { explicit location( char const* file_name = 0, size_t line_num = 0, char const* func = 0 ); const_string m_file_name; size_t m_line_num; const_string m_function; }; // Constructor execution_exception( error_code ec_, const_string what_msg_, location const& location_ ); // max length 256 inc '\0' // Access methods error_code code() const { return m_error_code; } const_string what() const { return m_what; } location const& where() const { return m_location; } }; // execution_exception class execution_monitor { typedef boost::unit_test::const_string const_string; public: execution_monitor(); // Public properties // The p_catch_system_errors parameter specifies whether the monitor should // try to catch system errors/exceptions that would cause program to crash // in regular case unit_test::readwrite_property<bool> p_catch_system_errors; // The p_auto_start_dbg parameter specifies whether the monitor should // try to attach debugger in case of caught system error unit_test::readwrite_property<bool> p_auto_start_dbg; // The p_timeout parameter specifies the seconds that elapse before // a timer_error occurs. May be ignored on some platforms. unit_test::readwrite_property<int> p_timeout; // The p_use_alt_stack parameter specifies whether the monitor should // use alternative stack for the signal catching unit_test::readwrite_property<bool> p_use_alt_stack; // The p_detect_fp_exceptions parameter specifies whether the monitor should // try to detect hardware floating point exceptions (!= 0), and which specific exception to catch unit_test::readwrite_property<unsigned> p_detect_fp_exceptions; int execute( boost::function<int ()> const& F ); // Returns: Value returned by function call F(). // // Effects: Calls executes supplied function F inside a try/catch block which also may // include other unspecified platform dependent error detection code. // // Throws: execution_exception on an uncaught C++ exception, // a hardware or software signal, trap, or other exception. // // Note: execute() doesn't consider it an error for F to return a non-zero value. void vexecute( boost::function<void ()> const& F ); // Effects: Same as above, but returns nothing // register custom (user supplied) exception translator template<typename ExceptionType, typename ExceptionTranslator> void register_exception_translator( ExceptionTranslator const& tr, const_string tag = const_string(), boost::type<ExceptionType>* = 0 ); // erase custom exception translator void erase_exception_translator( const_string tag ) { m_custom_translators = m_custom_translators->erase( m_custom_translators, tag ); } template<typename ExceptionType> void erase_exception_translator( boost::type<ExceptionType>* = 0 ) { m_custom_translators = m_custom_translators->erase<ExceptionType>( m_custom_translators ); } }; // execution_monitor template<typename ExceptionType, typename ExceptionTranslator> void execution_monitor::register_exception_translator( ExceptionTranslator const& tr, const_string tag, boost::type<ExceptionType>* ) { m_custom_translators.reset( new detail::translator_holder<ExceptionType,ExceptionTranslator>( tr, m_custom_translators, tag ) ); } struct execution_aborted {}; class system_error { public: // Constructor explicit system_error( char const* exp ); unit_test::readonly_property<long> p_errno; unit_test::readonly_property<char const*> p_failed_exp; }; #define BOOST_TEST_SYS_ASSERT( exp ) if( (exp) ) ; else throw ::boost::system_error( BOOST_STRINGIZE( exp ) ) namespace fpe { enum masks { BOOST_FPE_OFF = 0, #ifdef BOOST_SEH_BASED_SIGNAL_HANDLING BOOST_FPE_DIVBYZERO = EM_ZERODIVIDE, BOOST_FPE_INEXACT = EM_INEXACT, BOOST_FPE_INVALID = EM_INVALID, BOOST_FPE_OVERFLOW = EM_OVERFLOW, BOOST_FPE_UNDERFLOW = EM_UNDERFLOW|EM_DENORMAL, BOOST_FPE_ALL = MCW_EM, #elif defined(BOOST_NO_FENV_H) || defined(BOOST_CLANG) BOOST_FPE_ALL = 1, #else BOOST_FPE_DIVBYZERO = FE_DIVBYZERO, BOOST_FPE_INEXACT = FE_INEXACT, BOOST_FPE_INVALID = FE_INVALID, BOOST_FPE_OVERFLOW = FE_OVERFLOW, BOOST_FPE_UNDERFLOW = FE_UNDERFLOW, BOOST_FPE_ALL = FE_ALL_EXCEPT, #endif BOOST_FPE_INV = BOOST_FPE_ALL+1 }; // return the previous set of enabled exceptions when successful, and BOOST_FPE_INV otherwise unsigned BOOST_TEST_DECL enable( unsigned mask ); unsigned BOOST_TEST_DECL disable( unsigned mask ); } // namespace fpe } // namespace boost
![]() |
Home | Libraries | People | FAQ | More |
When performing an exception
safety test, this argument forces a break into the debugger at
the named exection path point within the test
name. The test must be named exactly, no wildcards
are supported.
|
Value |
Meaning |
|---|---|
|
|
For test case |
Environment variable: BOOST_TEST_BREAK_EXEC_PATH
![]() |
Home | Libraries | People | FAQ | More |
This argument causes the test runner to report information about the
build environment before running the tests. If the argument is specified
but no value is given, then a value of yes is assumed.
|
Value |
Meaning |
|---|---|
|
|
Do not report build information. |
|
|
Report build information. |
Environment variable: BOOST_TEST_BUILD_INFO
![]() |
Home | Libraries | People | FAQ | More |
This argument controls whether or not the test runner catches fatal system errors.
|
Value |
Meaning |
|---|---|
|
|
Do not handle fatal system errors. |
|
|
Handle fatal system errors. |
Environment variable: BOOST_TEST_CATCH_SYSTEM_ERRORS
![]() |
Home | Libraries | People | FAQ | More |
On systems that support colored text output, this argument controls whether or not the test runner will color the output. This argument does nothing on systems that do not support colored text output.
|
Value |
Meaning |
|---|---|
|
|
Do not color test runner output. |
|
|
Color test runner output, if supported. |
Environment variable: BOOST_TEST_COLOR_OUTPUT
![]() |
Home | Libraries | People | FAQ | More |
If the execution environment supoprts floating-point exceptions, this argument controls whether or not the test runner will detect floating-point exceptions.
|
Value |
Meaning |
|---|---|
|
|
Do not detect floating-point exceptions. |
|
|
Detect floating-point exceptions, if supported. |
Environment variable: BOOST_TEST_DETECT_FP_EXCEPTIONS
![]() |
Home | Libraries | People | FAQ | More |
If the execution environment supports the detection of memory leaks, this argument controls whether or not the test runner reports memory leaks. After running the tests, a memory leak report is issued showing the allocation number and the amount of memory leaked.
Values greater than 1 for this argument cause a trap
to the debugger for a particular memory allocation number. Currently,
this option is only implemented for Microsoft compilers.
|
Value |
Meaning |
|---|---|
|
|
Do not detect memory leaks. |
|
|
Detect memory leaks and issue a memory leak report. |
|
|
Break on allocation |
Environment variable: BOOST_TEST_DETECT_MEMORY_LEAKS
![]() |
Home | Libraries | People | FAQ | More |
This argument controls the level of test runner output. The values are cumulative, with each increase in log level including all messages at lower levels. By default, only errors are reported. See test runner log for more information on the log.
|
Value |
Meaning |
|---|---|
|
|
Do not report any information. |
|
|
Report all user or system fatal errors, such as memory access violation. |
|
|
Report system non-fatal errors, such as timeout or floating-point exception. |
|
|
Report uncaught C++ exceptions. |
|
|
Report test failures. |
|
|
Report test warnings. |
|
|
Report test messages; see |
|
|
Report entering and leaving every test case and test suite. |
|
|
Report all successful assertions. |
|
|
Report everything. |
Environment variable: BOOST_TEST_LOG_LEVEL
![]() |
Home | Libraries | People | FAQ | More |
This argument controls the destination, or sink, of the test runner log. See test runner log for more information on the log.
|
Value |
Meaning |
|---|---|
|
|
The test runner log is sent to the standard output stream. |
|
|
The test runner log is sent to the standard error stream. |
|
|
The test runner log is sent to the file |
Environment variable: BOOST_TEST_LOG_SINK
![]() |
Home | Libraries | People | FAQ | More |
This argument combines --log_format
and --report_format.
See test runner log
for more information on the log. See test
runner report for more information on the report.
|
Value |
Meaning |
|---|---|
|
|
Human readable format output. |
|
|
XML format output. |
Environment variable: BOOST_TEST_OUTPUT_FORMAT
![]() |
Home | Libraries | People | FAQ | More |
This argument controls whether or not the test runner will execute tests in a random order. This argument can also provide a seed for the random number generator used to run tests in a random order.
|
Value |
Meaning |
|---|---|
|
|
Run tests in registration order. |
|
|
Run tests in a random order, using the current time as the seed. |
|
|
Run tests in a random order, using |
Environment variable: BOOST_TEST_RANDOM
![]() |
Home | Libraries | People | FAQ | More |
This argument controls the level of the test report. The levels are cumulative, with each successive level incorporating the output of all the previous levels.
|
Value |
Meaning |
|---|---|
|
|
No test report. |
|
|
Confirmation test report. |
|
|
Short test report. |
|
|
Detailed test report. |
Environment variable: BOOST_TEST_REPORT_LEVEL
![]() |
Home | Libraries | People | FAQ | More |
This argument controls the destination, or sink, of the test runner report. See test runner report for more information on the report.
|
Value |
Meaning |
|---|---|
|
|
The test report is sent to the standard output stream. |
|
|
The test report is sent to the standard error stream. |
|
|
The test report is sent to the file |
Environment variable: BOOST_TEST_REPORT_SINK
![]() |
Home | Libraries | People | FAQ | More |
This argument controls whether or not the test runner returns an exit code corresponding to a summary of the test execution or zero. The summary result code is determined as follows:
|
Result Code |
Description |
|---|---|
|
0 ( |
All executed tests passed. |
|
200 ( |
Failure due to uncaught exception. |
|
201 ( |
One or more executed tests failed. |
|
Value |
Meaning |
|---|---|
|
|
Always return zero. |
|
|
Return a status code indicating the summary of the tests executed. |
Environment variable: BOOST_TEST_RESULT_CODE
![]() |
Home | Libraries | People | FAQ | More |
This argument informs the test runner of a boolean value used to create
or save a test pattern for file-based testing. The test case uses the
boolean value to determine whether or not it writes the test pattern
by exercising the system under test or reads the test pattern for comparison
against the values produced by the system under test. The output_test_stream
class provides a facility for recording and matching against save patterns.
|
Value |
Meaning |
|---|---|
|
|
Match against a saved pattern. |
|
|
Save a pattern for matching. |
Environment variable: BOOST_TEST_SAVE_PATTERN
![]() |
Home | Libraries | People | FAQ | More |
This parameter instructs the test runner to print progress through the test cases. The test runner has no way of determining the length of time each test case will consume; the progress percentage is determined by counting test cases.
|
Value |
Meaning |
|---|---|
|
|
Do not show test execution progress. |
|
|
Show test execution progress. |
Environment variable: BOOST_TEST_SHOW_PROGRESS
![]() |
Home | Libraries | People | FAQ | More |
This parameter instructs the test runner to use an alternate stack for signals processing on platforms where this is supported.
|
Value |
Meaning |
|---|---|
|
|
Do not use an alternate stack. |
|
|
Use an alternate stack, where supported. |
Environment variable: BOOST_TEST_USE_ALT_STACK
![]() |
Home | Libraries | People | FAQ | More |
This argument controls whether or not a debugger is attached to the test runner when a fatal system error occurs. A fatal system error includes Unix/POSIX signals, C++ exceptions and Win32 structured exceptions.
|
Value |
Meaning |
|---|---|
|
|
Do not attach a debugger to when a fatal system error occurs. |
|
|
Attach the default debugger when a fatal system error occurs. |
Environment variable: BOOST_TEST_AUTO_START_DBG
![]() |
Home | Libraries | People | FAQ | More |
This argument instructs the test runner to print out an indented listing of all test suites and test cases registered with the test runner without running the tests.
|
Value |
Meaning |
|---|---|
|
|
Do not list test suites and cases. |
|
|
List test suites and cases and exit without running tests. |
Environment variable: BOOST_TEST_LIST_CONTENT
![]() |
Home | Libraries | People | FAQ | More |
This argument controls the format of the test runner output. The value is case insensitive. See test runner log for more information on the log.
|
Value |
Meaning |
|---|---|
|
|
Human readable format output. |
|
|
XML format output. |
Environment variable: BOOST_TEST_LOG_FORMAT
![]() |
Home | Libraries | People | FAQ | More |
This argument controls the level of test runner output. The values are cumulative, with each increase in log level including all messages at lower levels. By default, only errors are reported. See test runner log for more information on the log.
|
Value |
Meaning |
|---|---|
|
|
Do not report any information. |
|
|
Report all user or system fatal errors, such as memory access violation. |
|
|
Report system non-fatal errors, such as timeout or floating-point exception. |
|
|
Report uncaught C++ exceptions. |
|
|
Report test failures. |
|
|
Report test warnings. |
|
|
Report test messages; see |
|
|
Report entering and leaving every test case and test suite. |
|
|
Report all successful assertions. |
|
|
Report everything. |
Environment variable: BOOST_TEST_LOG_LEVEL
![]() |
Home | Libraries | People | FAQ | More |
This argument controls the destination, or sink, of the test runner log. See test runner log for more information on the log.
|
Value |
Meaning |
|---|---|
|
|
The test runner log is sent to the standard output stream. |
|
|
The test runner log is sent to the standard error stream. |
|
|
The test runner log is sent to the file |
Environment variable: BOOST_TEST_LOG_SINK
![]() |
Home | Libraries | People | FAQ | More |
This argument combines --log_format
and --report_format.
See test runner log
for more information on the log. See test
runner report for more information on the report.
|
Value |
Meaning |
|---|---|
|
|
Human readable format output. |
|
|
XML format output. |
Environment variable: BOOST_TEST_OUTPUT_FORMAT
![]() |
Home | Libraries | People | FAQ | More |
This argument controls the format of the test report. See test runner report for more information on the report.
|
Value |
Meaning |
|---|---|
|
|
Human readable format output. |
|
|
XML format output. |
Environment variable: BOOST_TEST_REPORT_FORMAT
![]() |
Home | Libraries | People | FAQ | More |
This argument controls the level of the test report. The levels are cumulative, with each successive level incorporating the output of all the previous levels. See test runner report for more information on the report.
|
Value |
Meaning |
|---|---|
|
|
No test report. |
|
|
Confirmation test report. |
|
|
Short test report. |
|
|
Detailed test report. |
Environment variable: BOOST_TEST_REPORT_LEVEL
![]() |
Home | Libraries | People | FAQ | More |
This argument controls the destination, or sink, of the test runner report. See test runner report for more information on the report.
|
Value |
Meaning |
|---|---|
|
|
The test report is sent to the standard output stream. |
|
|
The test report is sent to the standard error stream. |
|
|
The test report is sent to the file |
Environment variable: BOOST_TEST_REPORT_SINK
![]() |
Home | Libraries | People | FAQ | More |
This argument controls which test cases will be executed. The value is a comma separated list of test specifiers. Test cases are arranged as leaves on a tree structure, with every test case belonging to a test suite. The test runner always creates a master test suite. Named test suites are children of the master test suite or another named test suite. Any test case that is not the child of a named test suite is a child of the unnamed master test suite.
Test specifiers select test cases or suites by naming the path from the
unnamed master test suite to the case or suite, similar to a full path
to a file in a hierarchical directory structure. A test specifier is
one or more path specifiers, separated by a slash (/).
A test specifier begins at the master test suite and proceeds down the
test tree, naming suites or test cases.
The argument --report_level
set to detailed can be used to output the names of
all the test suites and test cases within those test suites.
|
Path Specifier |
Tests Selected |
|---|---|
|
|
The test case or suite named |
|
|
All test cases or suites whose name ends in |
|
|
All test cases or suites whose name begins with |
|
|
All test cases or suites whose name contains |
|
|
All test cases or suites. |
|
|
The test cases or suites with the given specifier. |
|
|
The test cases or suites matched by |
Environment variable: BOOST_TESTS_TO_RUN
![]() |
Home | Libraries | People | FAQ | More |
Table 1.3. Command Line Argument Summary
|
Argument |
Description |
|---|---|
|
|
Automatically attach debugger in case of system failure |
|
|
Print build information |
|
|
Catch system errors |
|
|
Detect floating-point exceptions |
|
|
Detect memory leaks |
|
|
Print out a summary of test runner options |
|
|
The format of the test log |
|
|
The level of logging reported |
|
|
The log sink name |
|
|
The output format |
|
|
Random number seed |
|
|
The test results report format |
|
|
The test results report level |
|
|
The report sink name |
|
|
Return result code |
|
|
Tests to run |
|
|
Show execution progress |
|
|
Use alternative stack |
|
|
Wait for the debugger to attach to the test runner. |
The functionality of each command-line option can also be invoked with an environment variable. The description for each option gives the environment variable associated with that option.
![]() |
Home | Libraries | People | FAQ | More |
BOOST_TEST_CHECKPOINT(message)
registers a test case checkpoint and associated message
with the test runner. A checkpoint includes the source file and line
number where the macro was invoked. If the test case is aborted unexpectedly,
the source location and message associated with the last registered checkpoint
is emitted into the log. Checkpoints can be used to identify the location
of an unexpected failure within a block of test case code. The message
is applied to an output stream with operator<< and can include other invocations
of operator<<.
BOOST_AUTO_TEST_CASE(example_checkpoint) { int const i = 0; BOOST_TEST_CHECKPOINT("i = " << i); BOOST_REQUIRE(i == 0); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_TEST_PASSPOINT() is similar to BOOST_TEST_CHECKPOINT,
but only registers a source file location with the test runner.
BOOST_AUTO_TEST_CASE(example_passpoint) { BOOST_TEST_PASSPOINT(); throw std::runtime_error("Oops"); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_TEST_CHECKPOINT(message)
registers a test case checkpoint and associated message
with the test runner. A checkpoint includes the source file and line
number where the macro was invoked. If the test case is aborted unexpectedly,
the source location and message associated with the last registered checkpoint
is emitted into the log. Checkpoints can be used to identify the location
of an unexpected failure within a block of test case code. The message
is applied to an output stream with operator<< and can include other invocations
of operator<<.
BOOST_AUTO_TEST_CASE(example_checkpoint) { int const i = 0; BOOST_TEST_CHECKPOINT("i = " << i); BOOST_REQUIRE(i == 0); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_TEST_MESSAGE(message)
unconditionally writes the message into the
test runner log file. Unlike BOOST_TEST_CHECKPOINT
no file and line number information is written into the log file. The
message is applied to an output stream with
operator<<
and can include other invocations of operator<<.
BOOST_AUTO_TEST_CASE(example_test_message) { int const i = 0; BOOST_TEST_MESSAGE("i = " << i); BOOST_REQUIRE(i == 0); }
![]() |
Home | Libraries | People | FAQ | More |
The test log contains detailed information on every assertion in every test case. The log can be formatted as plain human readable text or as XML and can be sent to the standard output stream, the standard error stream or a file.
The amount of detail in the log is set with the --log_level
option. The format of the log is set with the --log_format
option. The destination of the log is set with the --log_sink
option. The --output_format
option sets both the log format and the report format.
The XML format for the test log conforms to the schema UTF.log.xsd.
![]() |
Home | Libraries | People | FAQ | More |
The report contains summary information about the test cases executed and the count of failures. The report can be formatted as plain human readable text or as XML and can be sent to the standard output stream, standard error stream or a file.
The amount of detail in the report is controlled by the --report_level
option. The format of the report can be changed with the --report_format
option. The destination of the report can be set with the --report_sink
option. The --output_format
option sets both the report format and the log format.
The XML format for the test report conforms to the schema UTF.report.xsd.
![]() |
Home | Libraries | People | FAQ | More |
![]() |
Home | Libraries | People | FAQ | More |
![]() |
Home | Libraries | People | FAQ | More |
![]() |
Home | Libraries | People | FAQ | More |
![]() |
Home | Libraries | People | FAQ | More |
BOOST_AUTO_TEST_CASE(name)
creates a test case class, a test case invocation function, a test case
unique identifier, registers the invocation function as a test case and
begins the definition of the test method on the test class. The test case
class name is derived from BOOST_AUTO_TEST_CASE_FIXTURE
and contains a single method named test_method. The
test invocation function instantiates the test case class and invokes the
test case method. Test log checkpoints are made before the test case class
is instantiated and bracketing the test method invocation. This provides
diagnostic checkpoints should a runtime error cause a test case to be aborted
before any assertions are made.
![]() |
Home | Libraries | People | FAQ | More |
BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(name,
n) is used to decorate a
test case with an expected failure count of n.
It should appear immediately preceding the macro that defines the test
case, such as BOOST_AUTO_TEST_CASE
or BOOST_FIXTURE_TEST_CASE.
It can be used for test cases declared at file scope or within a test suite.
This macro should only be used in the most exceptional of circumstances.
Unit tests are designed to provide a safety net of regression tests against
our code. If we allow tests to stay failing, we are less motivated to correct
them.
As a temporary measure, we may wish to annotate certain tests as known
failures. The count n is the number of expected
failed assertions during the execution of the test case. When using the
CHECK
level assertions, the total failure count can be larger than one since
the test case continues executing past a failed assertion. When using
REQUIRE level assertions, the total failure count will
only be one as execution of the test case terminates on the first failed
assertion.
If CHECK level assertions are used and the number of
failures is less than or equal to n, the test
runner will return a status code of 0. If the number
of failures is greather than n, the test runner
will return a status code of 201. If REQUIRE
level assertions are used, the number of expected failures can be at most
one and the test runner will return a status code of 200
when one failed assertion is found.
BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(inserts_text_require_expected, 1) BOOST_AUTO_TEST_CASE(inserts_text_require_expected) { std::ostringstream dest; hello_world(dest); BOOST_REQUIRE_EQUAL("scooby-doo", dest.str()); }
![]() |
Note |
|---|---|
When using the compiler formatted test output, Visual Studio interprets the failed assertion output as a detected error, it will fail the Post-Build event mechanism recommended in Test Case Design and Maintenance. |
![]() |
Home | Libraries | People | FAQ | More |
BOOST_AUTO_TEST_CASE_TEMPLATE(name,
var, types)
declares a test case name parameterized by a
single template argument var that is evaluated
for each type in types. This allows you to write
a test case that exercises an invariant across a collection of types. The
macro expands into one test case for each type in types,
with the template argument var assigned to each
type. The types argument must be a Boost.MPL
type list and must be defined as a typedef.
#include <boost/mpl/list.hpp> #include <limits> typedef boost::mpl::list< unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long> unsigned_types; BOOST_AUTO_TEST_CASE_TEMPLATE(not_is_signed_for_unsigned_types, T, unsigned_types) { BOOST_REQUIRE(!std::numeric_limits<T>::is_signed); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_FIXTURE_TEST_CASE(name,
fixture) defines a test case
class name that derives from fixture.
If the test case is declared within a test suite that also has a test fixture,
then to get the cumulative effect of both fixtures the test case fixture
should derive from the test suite's fixture. Otherwise, the test case fixture
will replace the test suite fixture for a test case defined with BOOST_FIXTURE_TEST_CASE.
![]() |
Home | Libraries | People | FAQ | More |
BOOST_GLOBAL_FIXTURE(name)
declares a global fixture that is constructed before executing any test
cases and is destroyed after executing all test cases. If more than one
global fixture is defined in a single source file, the fixtures are constructed
in the order they appear in the source file and destroyed in the reverse
order. If global fixtures are defined in multiple source files, the order
in which global fixtures are initialized between source files is implementation
dependent.
Because global fixtures are not created and destroyed for each test case,
they represent shared state that prevents test cases from executing independently
from each other. For this reason, test case fixtures created with BOOST_FIXTURE_TEST_CASE
and test suite fixtures created with BOOST_FIXTURE_TEST_SUITE
are preferred over global fixtures.
struct global_fixture { global_fixture() { std::cout << "global setup\n"; } ~global_fixture() { std::cout << "global teardown\n"; } }; BOOST_GLOBAL_FIXTURE(global_fixture);
![]() |
Home | Libraries | People | FAQ | More |
BOOST_PARAM_CLASS_TEST_CASE(memfn,
instance, begin,
end) works similarly to
BOOST_PARAM_TEST_CASE.
It creates a collection of test cases that invoke the member function
memfn on the instance pointer instance.
The member function is passed an item obtained by iterating the collection
defined by the begin and end
iterators. The instance pointer must be passed
as a boost::shared_ptr to ensure the lifetime of the
instance exceeds that of any test case using the instance. The test case
returned by BOOST_PARAM_CLASS_TEST_CASE must be added
to a test suite in an initialization function for the tests to be executed.
#include <boost/make_shared.hpp> #include <boost/shared_ptr.hpp> using namespace boost::unit_test; class hello_world_tester { public: hello_world_tester() { eq_items.push_back("Hello, world!\n"); eq_items.push_back("Hello, world!\n"); ne_items.push_back("shaggy"); ne_items.push_back("scooby"); } void inserts_text(std::string const& text) { std::ostringstream dest; hello_world(dest); BOOST_REQUIRE_EQUAL(text, dest.str()); }; void does_not_insert_text(std::string const& text) { std::ostringstream dest; hello_world(dest); BOOST_REQUIRE_NE(text, dest.str()); } std::vector<std::string> eq_items; std::vector<std::string> ne_items; }; boost::shared_ptr<hello_world_tester> tester(boost::make_shared<hello_world_tester>()); static test_suite* init(int argc, char* argv[]) { test_suite& suite = framework::master_test_suite(); suite.add(BOOST_PARAM_CLASS_TEST_CASE( &hello_world_tester::inserts_text, tester, tester->eq_items.begin(), tester->eq_items.end())); suite.add(BOOST_PARAM_CLASS_TEST_CASE( &hello_world_tester::does_not_insert_text, tester, tester->ne_items.begin(), tester->ne_items.end())); return 0; } int main(int argc, char* argv[]) { return unit_test_main(init, argc, argv); }
![]() |
Note |
|---|---|
The single |
![]() |
Home | Libraries | People | FAQ | More |
BOOST_PARAM_TEST_CASE(fn,
begin, end)
creates a series of test cases that invoking the callable object fn
on the items in the collection defined by begin
and end. The test case returned by BOOST_PARAM_TEST_CASE
must be added to a test suite in an initialization function for the tests
to be executed. The iterators begin and end
must be valid at the time the test case executes and not just at the time
the test case is created.
using namespace boost::unit_test; static void does_not_insert_text(std::string const& text) { std::ostringstream dest; hello_world(dest); BOOST_REQUIRE_NE(text, dest.str()); } static std::vector<std::string> text; static test_suite* init(int argc, char* argv[]) { text.push_back("scooby"); text.push_back("shaggy"); text.push_back("foo"); text.push_back("arg"); framework::master_test_suite() .add(BOOST_PARAM_TEST_CASE(does_not_insert_text, text.begin(), text.end())); return 0; } int main(int argc, char* argv[]) { return unit_test_main(init, argc, argv); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_TEST_CASE(fn)
creates a new test case named "fn" that executes the callable
function fn. The test case returned by BOOST_TEST_CASE
must be added to a test suite in an initialization function for the tests
to be executed.
#define BOOST_TEST_NO_MAIN #include <boost/test/included/unit_test.hpp> #include "hello.hpp" #include <sstream> using namespace boost::unit_test; static void inserts_text() { std::ostringstream dest; hello_world(dest); BOOST_REQUIRE_EQUAL("Hello, world!\n", dest.str()); } static test_suite* init(int argc, char* argv[]) { framework::master_test_suite().add(BOOST_TEST_CASE(inserts_text)); return 0; } int main(int argc, char* argv[]) { return unit_test_main(init, argc, argv); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_TEST_CASE_TEMPLATE(name,
types) manually creates a
set of test cases from the template test case name
for each type in types. The test case returned
by BOOST_TEST_CASE_TEMPLATE must be added to a test
suite in an initialization function for the tests to be executed. The test
case function is defined with the BOOST_TEST_CASE_TEMPLATE_FUNCTION
macro.
static test_suite* init(int argc, char* argv[]) { test_suite& suite(framework::master_test_suite()); suite.add(BOOST_TEST_CASE_TEMPLATE(not_is_signed_for_unsigned_types, unsigned_types)); suite.add(BOOST_TEST_CASE_TEMPLATE(is_signed_for_signed_types, signed_types)); return 0; } int main(int argc, char* argv[]) { return unit_test_main(init, argc, argv); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_TEST_CASE_TEMPLATE_FUNCTION(name,
T) defines a test case function
named name that is parameterized by a type parameter
T. The defined functions are then available
for registration as parameterized test cases with BOOST_TEST_CASE_TEMPLATE.
typedef boost::mpl::list< char, short, int, long, long long> signed_types; BOOST_TEST_CASE_TEMPLATE_FUNCTION(is_signed_for_signed_types, T) { BOOST_REQUIRE(std::numeric_limits<T>::is_signed); }
![]() |
Home | Libraries | People | FAQ | More |
A test case is a named body of code providing the three phases of a test: setup, exercise and verify. A test case is most conveniently created using one of the provided test case macros listed in the following table.
Table 1.1. Test Case Macros
|
Macro |
Description |
|---|---|
|
|
Creates test case |
|
|
Informs the test runner that test case |
|
|
Automatically registers a test case |
|
|
Creates test case |
|
|
Manually creates a parameterized test case using the supplied callable
object |
|
|
Manually creates a parameterized test case using the supplied callable
object |
|
|
Manually creates a test case using the supplied callable object
|
|
|
Manually creates a set of test cases from the template test case
|
|
|
Manually creates a template test case |
![]() |
Home | Libraries | People | FAQ | More |
BITWISE_level_EQUAL(lhs,
rhs) compares the two arguments
for bitwise equality and fails if they are not equal. This can be useful
when testing integral values that represent a logical or combination
of bit flags.
enum bit_flags { source_file = 1u, header_file = 2u, build_file = 4u }; BOOST_AUTO_TEST_CASE(example_bitwise_equal) { BOOST_REQUIRE_BITWISE_EQUAL( source_file | build_file, build_file | source_file); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_CLOSE(lhs,
rhs, tolerance)
compares the two floating-point arguments and considers them equal if
they agree within the given tolerance. The
tolerance is given as a percentage.
BOOST_AUTO_TEST_CASE(example_close) { BOOST_REQUIRE_CLOSE(100.f, 100.9f, 1.f); BOOST_REQUIRE_CLOSE(100.f, 99.1f, 1.f); }
TODO: link to floating-point algorithm explanation
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_CLOSE_FRACTION(lhs,
rhs, tolerance)
compares the two floating-point arguments and considers them equal if
they agree within the given tolerance. The
tolerance is given as a percentage.
BOOST_AUTO_TEST_CASE(example_close_fraction) { BOOST_REQUIRE_CLOSE_FRACTION(100.f, 100.9f, 1.f); BOOST_REQUIRE_CLOSE_FRACTION(100.f, 99.1f, 1.f); }
TODO: link to floating-point algorithm explanation
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level=_EQUAL_COLLECTIONS(lhs_begin,
lhs_end, rhs_begin,
rhs_end) compares two collections
for equality. Two collections are considered equal if they have the same
number of elements and the elements compare equal by operator==. The elements are obtained through
the supplied iterators on the collections. The diagnostic message is
constructed from applying operator<< to each of the elements in the
collections.
![]() |
Important |
|---|---|
If you get a strange compile error when using |
BOOST_AUTO_TEST_CASE(example_equal_collections) { std::vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); std::list<int> l; l.push_front(3); l.push_front(2); l.push_front(1); BOOST_REQUIRE_EQUAL_COLLECTIONS(v.begin(), v.end(), l.begin(), l.end()); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_EXCEPTION(statement,
exception, predicate)
asserts that when statement throws an exception
of type exception, the predicate
applied to the instance of the exception returns true.
This is used to verify not only that an exception of the correct type
was thrown, but that the contents of the thrown exception meet the expectations
of the predicate.
class error_number_exception { public: error_number_exception(int num) : num_(num) { } int error_number() const { return num_; } private: int num_; }; bool has_error_number_1(error_number_exception const& ex) { return ex.error_number() == 1; } BOOST_AUTO_TEST_CASE(example_exception) { BOOST_REQUIRE_EXCEPTION(throw error_number_exception(1), error_number_exception, has_error_number_1); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_GE(lhs,
rhs) asserts that lhs
is greater than or equal to rhs. The comparison
is made by applying operator>= to both arguments. The diagnostic
message is constructed from applying operator<< to the two arguments.
![]() |
Important |
|---|---|
If you get a strange compile error when using |
BOOST_AUTO_TEST_CASE(example_ge) { // integral types unsigned const u = 1u; int const i = -10; char const A = 'A'; // standard library types providing operator>= and operator<< std::string const s = "scooby"; BOOST_REQUIRE_GE(2u, u); BOOST_REQUIRE_GE(1u, u); BOOST_REQUIRE_GE(-9, i); BOOST_REQUIRE_GE(-10, i); BOOST_REQUIRE_GE('B', A); BOOST_REQUIRE_GE('A', A); BOOST_REQUIRE_GE("scoobz", s); BOOST_REQUIRE_GE("scooby", s); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_GT(lhs,
rhs) asserts that lhs
is greater than rhs. The comparison is made
by applying operator>
to both arguments. The diagnostic message is constructed from applying
operator<<
to the two arguments.
![]() |
Important |
|---|---|
If you get a strange compile error when using |
BOOST_AUTO_TEST_CASE(example_gt) { // integral types unsigned const u = 1u; int const i = -10; char const A = 'A'; // standard library types providing operator> and operator== std::string const s = "scooby"; BOOST_REQUIRE_GT(2u, u); BOOST_REQUIRE_GT(-9, i); BOOST_REQUIRE_GT('B', A); BOOST_REQUIRE_GT("scoobz", s); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_LE(lhs,
rhs) asserts that lhs
is less than or equal to rhs. The comparison
is made by applying operator<= to both arguments. The diagnostic
message is constructed from applying operator<< to the two arguments.
![]() |
Important |
|---|---|
If you get a strange compile error when using |
BOOST_AUTO_TEST_CASE(example_le) { // integral types unsigned const u = 10u; int const i = -10; char const M = 'M'; // standard library types providing operator>= and operator<< std::string const s = "scooby"; BOOST_REQUIRE_LE(9u, u); BOOST_REQUIRE_LE(10u, u); BOOST_REQUIRE_LE(-11, i); BOOST_REQUIRE_LE(-10, i); BOOST_REQUIRE_LE('L', M); BOOST_REQUIRE_LE('M', M); BOOST_REQUIRE_LE("scoobx", s); BOOST_REQUIRE_LE("scooby", s); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_LT(lhs,
rhs) asserts that lhs
is less than rhs. The comparison is made by
applying operator<
to both arguments. The diagnostic message is constructed from applying
operator<<
to the two arguments.
![]() |
Important |
|---|---|
If you get a strange compile error when using |
BOOST_AUTO_TEST_CASE(example_lt) { // integral types unsigned const u = 10u; int const i = -10; char const M = 'M'; // standard library types providing operator>= and operator<< std::string const s = "scooby"; BOOST_REQUIRE_LT(9u, u); BOOST_REQUIRE_LT(-11, i); BOOST_REQUIRE_LT('L', M); BOOST_REQUIRE_LT("scoobx", s); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_MESSAGE(predicate,
message) emits message
if the supplied predicate evaluates to false.
The message is applied to an output stream
with operator<<
and the argument can contain additional applications of operator<<
for building up complex messages. The predicate can return bool
or __predicate_result__.
static int g_i; // simple predicate static bool global_int_is_positive() { return g_i > 0; } // predicate that builds up detail message static boost::test_tools::predicate_result global_int_equal(int expected) { if (g_i == expected) { return true; } boost::test_tools::predicate_result failed = false; failed.message() << "g_i != " << expected << "; actual: " << g_i; return failed; } BOOST_AUTO_TEST_CASE(example_message) { g_i = 1; BOOST_REQUIRE_MESSAGE(global_int_is_positive(), "g_i is not positive; actual: " << g_i); BOOST_REQUIRE_MESSAGE(global_int_equal(1), ""); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_NE(lhs,
rhs) asserts that lhs
is not equal to rhs. The comparison is made
by applying operator!=
to both arguments. The diagnostic message is constructed from applying
operator<<
to the two arguments.
![]() |
Important |
|---|---|
If you get a strange compile error when using |
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_NO_THROW(statement)
asserts that statement does not throw an exception.
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_PREDICATE(predicate,
args) asserts that the
supplied predicate applied to args
evaluates to true.
![]() |
Home | Libraries | People | FAQ | More |
![]() |
Home | Libraries | People | FAQ | More |
BOOST_TEST_DONT_PRINT_LOG_VALUE(type)
instructs the test framework to ignore values of type type
when constructing diagnostic messages. It does this by defining an empty
implementation of a print function specialized for type.
![]() |
Home | Libraries | People | FAQ | More |
BOOST_TEST_ERROR(message)
always fails and emits the given message at
the CHECK assertion level.
![]() |
Home | Libraries | People | FAQ | More |
BOOST_TEST_IS_DEFINED(symbol)
asserts that symbol is a defined value.
![]() |
Home | Libraries | People | FAQ | More |
BOOST_TEST_FAIL(message)
always fails and emits the given message at
the REQUIRE assertion level.
![]() |
Home | Libraries | People | FAQ | More |
BOOST_EQUAL(lhs, rhs)
compares the two arguments with operator==. The diagnostic message is constructed
with operator<<
on the two arguments.
![]() |
Important |
|---|---|
If you get a strange compile error when using |
BOOST_AUTO_TEST_CASE(example_equal) { // integral types unsigned const u = 1u; int const i = -1; char const A = 'A'; // standard library types providing operator== and operator<< std::string const s = "scooby"; BOOST_REQUIRE_EQUAL(1u, u); BOOST_REQUIRE_EQUAL(-1, i); BOOST_REQUIRE_EQUAL('A', A); BOOST_REQUIRE_EQUAL("scooby", s); }
// custom data structure struct symbol { char const* const name; int value; }; // custom comparison operator bool operator==(symbol const& lhs, symbol const& rhs) { return lhs.value == rhs.value && std::string(lhs.name) == std::string(rhs.name); } // custom stream insertion operator std::ostream& operator<<(std::ostream& stream, symbol const& value) { return stream << value.name << ": " << value.value; } BOOST_AUTO_TEST_CASE(example_equal_custom_compare) { symbol const s1 = { "var" , 1 }; symbol const s2 = { "var", 1 }; // If the compiler doesn't collapse multiple constants, then: // s1.name != s2.name; BOOST_REQUIRE_EQUAL(s1, s2); }
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_THROW(statement,
exception) asserts that
statement throws an exception of type exception.
![]() |
Home | Libraries | People | FAQ | More |
When using the library or header-only version of Boost.Test, many assertion macros are provided in three levels that determine the behavior when the assertion fails and how a failed assertion interacts with the test runner.
Table 1.2. Assertion Levels
|
Level |
Test Case Fails? |
Aborts Execution? |
|---|---|---|
|
|
No |
No |
|
|
Yes |
no |
|
|
Yes |
Yes |
The WARN level issues a diagnostic message, but the
test case is not considered to have failed and continues executing. The
CHECK level issues a message to the test log on failure,
marks the test case as failed and continues executing. The REQUIRE
level issues a message to the test log on failure, marks the test case
as failed and halts execution of the test case.
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_BITWISE_EQUALBOOST_level_CLOSEBOOST_level_CLOSE_FRACTIONBOOST_level_EQUALBOOST_level_EQUAL_COLLECTIONSBOOST_level_EXCEPTIONBOOST_level_GEBOOST_level_GTBOOST_level_LEBOOST_level_LTBOOST_level_MESSAGEBOOST_level_NEBOOST_level_NO_THROWBOOST_level_PREDICATEBOOST_level_SMALLBOOST_level_THROWBOOST_TEST_ERRORBOOST_TEST_FAILBOOST_TEST_IS_DEFINEDBOOST_TEST_DONT_PRINT_LOG_VALUEAssertions are used to validate the result of exercising the system under test. When an assertion fails, a diagnostic message is created and the failed assertion is recorded. Different assertion levels allow you to control how a failed assertion is interpreted by the test runner.
![]() |
Important |
|---|---|
When an assertion involves a user-defined datatype, a stream insertion
operator ( |
The minimal header test framework does not provide the facilities described here.
![]() |
Home | Libraries | People | FAQ | More |
#include <boost/test/debug.hpp>
namespace boost { namespace test { bool under_debugger(); void debugger_break(); struct dbg_startup_info { long pid; bool break_or_continue; unit_test::const_string binary_path; unit_test::const_string display; unit_test::const_string init_done_lock; }; typedef boost::function<void (dbg_startup_info const&)> dbg_starter; std::string set_debugger( unit_test::const_string dbg_id, dbg_starter s = dbg_starter() ); bool attach_debugger( bool break_or_continue = true ); void detect_memory_leaks( bool on_off, unit_test::const_string report_file = unit_test::const_string() ); void break_memory_alloc( long mem_alloc_order_num ); }} // boost::test
#include <boost/test/debug_config.hpp
BOOST_TEST_DBG_LIST BOOST_TEST_STAT_LINE_MAX
#include <boost/test/execution_monitor.hpp>
namespace boost { class execution_exception { typedef boost::unit_test::const_string const_string; public: enum error_code { no_error = 0, user_error = 200, cpp_exception_error = 205, system_error = 210, timeout_error = 215, user_fatal_error = 220, system_fatal_error = 225 }; struct BOOST_TEST_DECL location { explicit location( char const* file_name = 0, size_t line_num = 0, char const* func = 0 ); const_string m_file_name; size_t m_line_num; const_string m_function; }; // Constructor execution_exception( error_code ec_, const_string what_msg_, location const& location_ ); // max length 256 inc '\0' // Access methods error_code code() const { return m_error_code; } const_string what() const { return m_what; } location const& where() const { return m_location; } }; // execution_exception class execution_monitor { typedef boost::unit_test::const_string const_string; public: execution_monitor(); // Public properties // The p_catch_system_errors parameter specifies whether the monitor should // try to catch system errors/exceptions that would cause program to crash // in regular case unit_test::readwrite_property<bool> p_catch_system_errors; // The p_auto_start_dbg parameter specifies whether the monitor should // try to attach debugger in case of caught system error unit_test::readwrite_property<bool> p_auto_start_dbg; // The p_timeout parameter specifies the seconds that elapse before // a timer_error occurs. May be ignored on some platforms. unit_test::readwrite_property<int> p_timeout; // The p_use_alt_stack parameter specifies whether the monitor should // use alternative stack for the signal catching unit_test::readwrite_property<bool> p_use_alt_stack; // The p_detect_fp_exceptions parameter specifies whether the monitor should // try to detect hardware floating point exceptions (!= 0), and which specific exception to catch unit_test::readwrite_property<unsigned> p_detect_fp_exceptions; int execute( boost::function<int ()> const& F ); // Returns: Value returned by function call F(). // // Effects: Calls executes supplied function F inside a try/catch block which also may // include other unspecified platform dependent error detection code. // // Throws: execution_exception on an uncaught C++ exception, // a hardware or software signal, trap, or other exception. // // Note: execute() doesn't consider it an error for F to return a non-zero value. void vexecute( boost::function<void ()> const& F ); // Effects: Same as above, but returns nothing // register custom (user supplied) exception translator template<typename ExceptionType, typename ExceptionTranslator> void register_exception_translator( ExceptionTranslator const& tr, const_string tag = const_string(), boost::type<ExceptionType>* = 0 ); // erase custom exception translator void erase_exception_translator( const_string tag ) { m_custom_translators = m_custom_translators->erase( m_custom_translators, tag ); } template<typename ExceptionType> void erase_exception_translator( boost::type<ExceptionType>* = 0 ) { m_custom_translators = m_custom_translators->erase<ExceptionType>( m_custom_translators ); } }; // execution_monitor template<typename ExceptionType, typename ExceptionTranslator> void execution_monitor::register_exception_translator( ExceptionTranslator const& tr, const_string tag, boost::type<ExceptionType>* ) { m_custom_translators.reset( new detail::translator_holder<ExceptionType,ExceptionTranslator>( tr, m_custom_translators, tag ) ); } struct execution_aborted {}; class system_error { public: // Constructor explicit system_error( char const* exp ); unit_test::readonly_property<long> p_errno; unit_test::readonly_property<char const*> p_failed_exp; }; #define BOOST_TEST_SYS_ASSERT( exp ) if( (exp) ) ; else throw ::boost::system_error( BOOST_STRINGIZE( exp ) ) namespace fpe { enum masks { BOOST_FPE_OFF = 0, #ifdef BOOST_SEH_BASED_SIGNAL_HANDLING BOOST_FPE_DIVBYZERO = EM_ZERODIVIDE, BOOST_FPE_INEXACT = EM_INEXACT, BOOST_FPE_INVALID = EM_INVALID, BOOST_FPE_OVERFLOW = EM_OVERFLOW, BOOST_FPE_UNDERFLOW = EM_UNDERFLOW|EM_DENORMAL, BOOST_FPE_ALL = MCW_EM, #elif defined(BOOST_NO_FENV_H) || defined(BOOST_CLANG) BOOST_FPE_ALL = 1, #else BOOST_FPE_DIVBYZERO = FE_DIVBYZERO, BOOST_FPE_INEXACT = FE_INEXACT, BOOST_FPE_INVALID = FE_INVALID, BOOST_FPE_OVERFLOW = FE_OVERFLOW, BOOST_FPE_UNDERFLOW = FE_UNDERFLOW, BOOST_FPE_ALL = FE_ALL_EXCEPT, #endif BOOST_FPE_INV = BOOST_FPE_ALL+1 }; // return the previous set of enabled exceptions when successful, and BOOST_FPE_INV otherwise unsigned BOOST_TEST_DECL enable( unsigned mask ); unsigned BOOST_TEST_DECL disable( unsigned mask ); } // namespace fpe } // namespace boost
![]() |
Home | Libraries | People | FAQ | More |
The init_unit_test_func function typedef identifies
the signature of the user supplied initialization function. The initialization
function can be used to add custom test cases and test suites to the test
tree.
namespace boost { namespace unit_test { #ifdef BOOST_TEST_ALTERNATIVE_INIT_API typedef bool (*init_unit_test_func)(); #else typedef test_suite* (*init_unit_test_func)( int, char* [] ); #endif } }
![]() |
Home | Libraries | People | FAQ | More |
The master test suite of type master_test_suite_t is
the starting point for the test runner.
namespace boost { namespace unit_test { class BOOST_TEST_DECL master_test_suite_t : public test_suite { public: master_test_suite_t() : test_suite( "Master Test Suite" ) , argc( 0 ) , argv( 0 ) {} // Data members int argc; char** argv; }; } }
You can obtain a reference to the master test suite with the master_test_suite()
function:
namespace boost { namespace unit_test { namespace framework { BOOST_TEST_DECL master_test_suite_t& master_test_suite(); } } }
![]() |
Home | Libraries | People | FAQ | More |
The init_unit_test_func function typedef identifies
the signature of the user supplied initialization function. The initialization
function can be used to add custom test cases and test suites to the
test tree.
namespace boost { namespace unit_test { #ifdef BOOST_TEST_ALTERNATIVE_INIT_API typedef bool (*init_unit_test_func)(); #else typedef test_suite* (*init_unit_test_func)( int, char* [] ); #endif } }
![]() |
Home | Libraries | People | FAQ | More |
The master test suite of type master_test_suite_t
is the starting point for the test runner.
namespace boost { namespace unit_test { class BOOST_TEST_DECL master_test_suite_t : public test_suite { public: master_test_suite_t() : test_suite( "Master Test Suite" ) , argc( 0 ) , argv( 0 ) {} // Data members int argc; char** argv; }; } }
You can obtain a reference to the master test suite with the master_test_suite()
function:
namespace boost { namespace unit_test { namespace framework { BOOST_TEST_DECL master_test_suite_t& master_test_suite(); } } }
![]() |
Home | Libraries | People | FAQ | More |
The test_case class represents a single test case.
A test case must be added to a test suite reachable from the master test
suite in order for the test runner to run the test case.
namespace boost { namespace unit_test { class BOOST_TEST_DECL test_case : public test_unit { public: enum { type = tut_case }; // Constructor test_case( const_string tc_name, callback0<> const& test_func ); // Access methods callback0<> const& test_func() const { return m_test_func; } }; } }
![]() |
Home | Libraries | People | FAQ | More |
The test_observer class encapsulates observers of
test execution. It provides a simple null style
observer behavior.
namespace boost { namespace unit_test { class BOOST_TEST_DECL test_observer { public: // test observer interface virtual void test_start( counter_t /* test_cases_amount */ ) {} virtual void test_finish() {} virtual void test_aborted() {} virtual void test_unit_start( test_unit const& ) {} virtual void test_unit_finish( test_unit const&, unsigned long /* elapsed */ ) {} virtual void test_unit_skipped( test_unit const& ) {} virtual void test_unit_aborted( test_unit const& ) {} virtual void assertion_result( bool /* passed */ ) {} virtual void exception_caught( execution_exception const& ) {} virtual int priority() { return 0; } }; } }
![]() |
Home | Libraries | People | FAQ | More |
The test_suite class represents a group of test cases
and suites in the test tree hierarchy.
namespace bosot { namespace unit_test { class BOOST_TEST_DECL test_suite : public test_unit { public: enum { type = tut_suite }; // Constructor explicit test_suite( const_string ts_name ); // test unit list management void add( test_unit* tu, counter_t expected_failures = 0, unsigned timeout = 0 ); void add( test_unit_generator const& gen, unsigned timeout = 0 ); void remove( test_unit_id id ); // access methods test_unit_id get( const_string tu_name ) const; std::size_t size() const { return m_members.size(); } }; } }
![]() |
Home | Libraries | People | FAQ | More |
The test_unit class forms the basis of the hierarchical
tree of test cases. Test applications will usually create instances of
test_case or test_suite, both of
which derive from test_unit.
namespace boost { namespace unit_test { class BOOST_TEST_DECL test_unit { public: enum { type = tut_any }; // Constructor test_unit( const_string tu_name, test_unit_type t ); // dependencies management void depends_on( test_unit* tu ); bool check_dependencies() const; // Public r/o properties typedef BOOST_READONLY_PROPERTY(test_unit_id,(framework_impl)) id_t; typedef BOOST_READONLY_PROPERTY(test_unit_id,(test_suite)) parent_id_t; readonly_property<test_unit_type> p_type; // type for this test unit readonly_property<const_string> p_type_name; // "case"/"suite" id_t p_id; // unique id for this test unit parent_id_t p_parent_id; // parent test suite id // Public r/w properties readwrite_property<std::string> p_name; // name for this test unit readwrite_property<unsigned> p_timeout; // timeout for the test unit execution readwrite_property<counter_t> p_expected_failures; // number of expected failures in this test unit mutable readwrite_property<bool> p_enabled; // enabled status for this unit void increase_exp_fail( unsigned num ); }; } }
![]() |
Home | Libraries | People | FAQ | More |
The unit_test_log_formatter class encapsulates formatting
of log events for an output stream.
namespace boost { namespace unit_test { class BOOST_TEST_DECL unit_test_log_formatter { public: enum log_entry_types { BOOST_UTL_ET_INFO, BOOST_UTL_ET_MESSAGE, BOOST_UTL_ET_WARNING, BOOST_UTL_ET_ERROR, BOOST_UTL_ET_FATAL_ERROR }; // Destructor virtual ~unit_test_log_formatter() {} // Formatter interface virtual void log_start( std::ostream&, counter_t test_cases_amount ) = 0; virtual void log_finish( std::ostream& ) = 0; virtual void log_build_info( std::ostream& ) = 0; virtual void test_unit_start( std::ostream&, test_unit const& tu ) = 0; virtual void test_unit_finish( std::ostream&, test_unit const& tu, unsigned long elapsed ) = 0; virtual void test_unit_skipped( std::ostream&, test_unit const& ) = 0; virtual void log_exception( std::ostream& os, log_checkpoint_data const& cd, execution_exception const& ex ) { // for backward compatibility log_exception( os, cd, ex.what() ); } virtual void log_exception( std::ostream&, log_checkpoint_data const&, const_string /* explanation */ ) {} virtual void log_entry_start( std::ostream&, log_entry_data const&, log_entry_types let ) = 0; virtual void log_entry_value( std::ostream&, const_string value ) = 0; virtual void log_entry_value( std::ostream&, lazy_ostream const& value ); // there is a default impl virtual void log_entry_finish( std::ostream& ) = 0; }; } }
![]() |
Home | Libraries | People | FAQ | More |
The unit_test_log_t class encapsulates the unit test
log. You obtain a reference to the single global unit test log instance
with the unit_test_log member.
namespace boost { namespace unit_test { namespace log { class BOOST_TEST_DECL unit_test_log_t : public test_observer, public singleton<unit_test_log_t> { public: // test_observer interface implementation void test_start( counter_t test_cases_amount ); void test_finish(); void test_aborted(); void test_unit_start( test_unit const& ); void test_unit_finish( test_unit const&, unsigned long elapsed ); void test_unit_skipped( test_unit const& ); void test_unit_aborted( test_unit const& ); void assertion_result( bool passed ); void exception_caught( execution_exception const& ); virtual int priority() { return 1; } // log configuration methods void set_stream( std::ostream& ); void set_threshold_level( log_level ); void set_format( output_format ); void set_formatter( unit_test_log_formatter* ); // test progress logging void set_checkpoint( const_string file, std::size_t line_num, const_string msg = const_string() ); // entry logging unit_test_log_t& operator<<( log::begin const& ); // begin entry unit_test_log_t& operator<<( log::end const& ); // end entry unit_test_log_t& operator<<( log_level ); // set entry level unit_test_log_t& operator<<( const_string ); // log entry value unit_test_log_t& operator<<( lazy_ostream const& ); // log entry value ut_detail::entry_value_collector operator()( log_level ); // initiate entry collection }; namespace { unit_test_log_t& unit_test_log; } } } }
![]() |
Home | Libraries | People | FAQ | More |
The unit_test_main function provides an implementation
of main that can be used by a test executable compiled
with BOOST_TEST_NO_MAIN.
namespace boost { namespace unit_test { int BOOST_TEST_DECL unit_test_main( init_unit_test_func init_func, int argc, char* argv[] ); } }
unit_test_main initializes the test framework, traverses
the test tree and reports the result as a the return value of the function.
Unexpected exceptions and system errors (signals, etc.) are caught and
mapped to appropriate return values by the function.
![]() |
Home | Libraries | People | FAQ | More |
The predicate_result class combines a boolean result
from a predicate with a detailed context message for a failed predicate
evaluation. Usually this class is only used in the internal implementation
of the test framework, but a user can define their own custom predicates
that return a predicate_result to support detailed failure
messages when an assertion fails.
predicate_result is constructable and assignable from
bool. The message() method returns
an output string stream that can be used to build up a context message.
namespace boost { namespace test_tools { class BOOST_TEST_DECL predicate_result { public: // Constructor predicate_result( bool pv_ ) : p_predicate_value( pv_ ) {} template<typename BoolConvertable> predicate_result( BoolConvertable const& pv_ ) : p_predicate_value( !!pv_ ) {} // Access methods bool operator!() const { return !p_predicate_value; } void operator=( bool pv_ ) { p_predicate_value.value = pv_; } operator safe_bool() const { return !!p_predicate_value ? &dummy::nonnull : 0; } // Public properties BOOST_READONLY_PROPERTY( bool, (predicate_result) ) p_predicate_value; // Access methods bool has_empty_message() const { return !m_message; } wrap_stringstream& message() const_string message() const { return !m_message ? const_string() : const_string( m_message->str() ); } }; } }
See BOOST_REQUIRE_MESSAGE
for an example using predicate_result.
![]() |
Home | Libraries | People | FAQ | More |
--auto_start_dbg--break_exec_path--build_info--catch_system_errors--color_output--detect_fp_exceptions--detect_memory_leaks--log_format--log_level--log_sink--output_format--random--report_format--report_level--report_sink--result_code--run_test--save_pattern--show_progress--use_alt_stackTable 1.3. Command Line Argument Summary
|
Argument |
Description |
|---|---|
|
|
Automatically attach debugger in case of system failure |
|
|
Break execution path |
|
|
Print build information |
|
|
Catch system errors |
|
|
Produce color output |
|
|
Detect floating-point exceptions |
|
|
Detect memory leaks |
|
|
Print out a summary of test runner options |
|
|
The format of the test log |
|
|
The level of logging reported |
|
|
The log sink name |
|
|
The output format |
|
|
Random number seed |
|
|
The test results report format |
|
|
The test results report level |
|
|
The report sink name |
|
|
Return result code |
|
|
Tests to run |
|
|
Save pattern |
|
|
Show execution progress |
|
|
Use alternative stack |
|
|
Wait for the debugger to attach to the test runner. |
The functionality of each command-line option can also be invoked with an environment variable. The description for each option gives the environment variable associated with that option.
This argument controls whether or not a debugger is attached to the test runner when a fatal system error occurs. A fatal system error includes Unix/POSIX signals, C++ exceptions and Win32 structured exceptions.
|
Value |
Meaning |
|---|---|
|
|
Do not attach a debugger to when a fatal system error occurs. |
|
|
Attach the default debugger when a fatal system error occurs. |
Environment variable: BOOST_TEST_AUTO_START_DBG
When performing an exception safety test, this argument forces a break
into the debugger at the named exection path
point within the test name. The test must
be named exactly, no wildcards are supported.
|
Value |
Meaning |
|---|---|
|
|
For test case |
Environment variable: BOOST_TEST_BREAK_EXEC_PATH
This argument causes the test runner to report information about the
build environment before running the tests. If the argument is specified
but no value is given, then a value of yes is assumed.
|
Value |
Meaning |
|---|---|
|
|
Do not report build information. |
|
|
Report build information. |
Environment variable: BOOST_TEST_BUILD_INFO
This argument controls whether or not the test runner catches fatal system errors.
|
Value |
Meaning |
|---|---|
|
|
Do not handle fatal system errors. |
|
|
Handle fatal system errors. |
Environment variable: BOOST_TEST_CATCH_SYSTEM_ERRORS
On systems that support colored text output, this argument controls whether or not the test runner will color the output. This argument does nothing on systems that do not support colored text output.
|
Value |
Meaning |
|---|---|
|
|
Do not color test runner output. |
|
|
Color test runner output, if supported. |
Environment variable: BOOST_TEST_COLOR_OUTPUT
If the execution environment supoprts floating-point exceptions, this argument controls whether or not the test runner will detect floating-point exceptions.
|
Value |
Meaning |
|---|---|
|
|
Do not detect floating-point exceptions. |
|
|
Detect floating-point exceptions, if supported. |
Environment variable: BOOST_TEST_DETECT_FP_EXCEPTIONS
If the execution environment supports the detection of memory leaks, this argument controls whether or not the test runner reports memory leaks. After running the tests, a memory leak report is issued showing the allocation number and the amount of memory leaked.
Values greater than 1 for this argument cause a
trap to the debugger for a particular memory allocation number. Currently,
this option is only implemented for Microsoft compilers.
|
Value |
Meaning |
|---|---|
|
|
Do not detect memory leaks. |
|
|
Detect memory leaks and issue a memory leak report. |
|
|
Break on allocation |
Environment variable: BOOST_TEST_DETECT_MEMORY_LEAKS
This argument controls the format of the test runner output. The value is case insensitive.
|
Value |
Meaning |
|---|---|
|
|
Human readable format output. |
|
|
XML format output. |
Environment variable: BOOST_TEST_LOG_FORMAT
This argument controls the level of test runner output. The values are cumulative, with each increase in log level including all messages at lower levels. By default, only errors are reported.
|
Value |
Meaning |
|---|---|
|
|
Do not report any information. |
|
|
Report all user or system fatal errors, such as memory access violation. |
|
|
Report system non-fatal errors, such as timeout or floating-point exception. |
|
|
Report uncaught C++ exceptions. |
|
|
Report test failures. |
|
|
Report test warnings. |
|
|
Report test messages; see |
|
|
Report entering and leaving every test case and test suite. |
|
|
Report all successful assertions. |
|
|
Report everything. |
Environment variable: BOOST_TEST_LOG_LEVEL
This argument controls the destination, or sink, of the test runner log.
|
Value |
Meaning |
|---|---|
|
|
The test runner log is sent to the standard output stream. |
|
|
The test runner log is sent to the standard error stream. |
|
|
The test runner log is sent to the file |
Environment variable: BOOST_TEST_LOG_SINK
This argument combines --log_format
and --report_format.
|
Value |
Meaning |
|---|---|
|
|
Human readable format output. |
|
|
XML format output. |
Environment variable: BOOST_TEST_OUTPUT_FORMAT
This argument controls whether or not the test runner will execute tests in a random order. This argument can also provide a seed for the random number generator used to run tests in a random order.
|
Value |
Meaning |
|---|---|
|
|
Run tests in registration order. |
|
|
Run tests in a random order, using the current time as the seed. |
|
|
Run tests in a random order, using |
Environment variable: BOOST_TEST_RANDOM
This argument controls the format of the test report.
|
Value |
Meaning |
|---|---|
|
|
Human readable format output. |
|
|
XML format output. |
Environment variable: BOOST_TEST_REPORT_FORMAT
This argument controls the level of the test report. The levels are cumulative, with each successive level incorporating the output of all the previous levels.
|
Value |
Meaning |
|---|---|
|
|
No test report. |
|
|
Confirmation test report. |
|
|
Short test report. |
|
|
Detailed test report. |
Environment variable: BOOST_TEST_REPORT_LEVEL
This argument controls the destination, or sink, of the test runner report.
|
Value |
Meaning |
|---|---|
|
|
The test report is sent to the standard output stream. |
|
|
The test report is sent to the standard error stream. |
|
|
The test report is sent to the file |
Environment variable: BOOST_TEST_REPORT_SINK
This argument controls whether or not the test runner returns an exit code corresponding to a summary of the test execution or zero. The summary result code is determined as follows:
|
Result Code |
Description |
|---|---|
|
0 ( |
All executed tests passed. |
|
200 ( |
Failure due to uncaught exception. |
|
201 ( |
One or more executed tests failed. |
|
Value |
Meaning |
|---|---|
|
|
Always return zero. |
|
|
Return a status code indicating the summary of the tests executed. |
Environment variable: BOOST_TEST_RESULT_CODE
This argument controls which test cases will be executed. The value is a comma separated list of test specifiers. Test cases are arranged as leaves on a tree structure, with every test case belonging to a test suite. The test runner always creates a master test suite. Named test suites are children of the master test suite or another named test suite. Any test case that is not the child of a named test suite is a child of the unnamed master test suite.
Test specifiers select test cases or suites by naming the path from
the unnamed master test suite to the case or suite, similar to a full
path to a file in a hierarchical directory structure. A test specifier
is one or more path specifiers, separated by a slash (/).
A test specifier begins at the master test suite and proceeds down
the test tree, naming suites or test cases.
The argument --report_level
set to detailed can be used to output the names
of all the test suites and test cases within those test suites.
|
Path Specifier |
Tests Selected |
|---|---|
|
|
The test case or suite named |
|
|
All test cases or suites whose name ends in |
|
|
All test cases or suites whose name begins with |
|
|
All test cases or suites whose name contains |
|
|
All test cases or suites. |
|
|
The test cases or suites with the given specifier. |
|
|
The test cases or suites matched by |
Environment variable: BOOST_TESTS_TO_RUN
This argument informs the test runner of a boolean value used to create
or save a test pattern for file-based testing. The test case uses the
boolean value to determine whether or not it writes the test pattern
by exercising the system under test or reads the test pattern for comparison
against the values produced by the system under test. The output_test_stream
class provides a facility for recording and matching against save patterns.
|
Value |
Meaning |
|---|---|
|
|
Match against a saved pattern. |
|
|
Save a pattern for matching. |
Environment variable: BOOST_TEST_SAVE_PATTERN
This parameter instructs the test runner to print progress through the test cases. The test runner has no way of determining the length of time each test case will consume; the progress percentage is determined by counting test cases.
|
Value |
Meaning |
|---|---|
|
|
|
|
|
Show test execution progress. |
Environment variable: BOOST_TEST_SHOW_PROGRESS
This parameter instructs the test runner to use an alternate stack for signals processing on platforms where this is supported.
|
Value |
Meaning |
|---|---|
|
|
|
|
|
Use an alternate stack, where supported. |
Environment variable: BOOST_TEST_USE_ALT_STACK
![]() |
Home | Libraries | People | FAQ | More |
BOOST_TEST_CHECKPOINT(message)
registers a test case checkpoint and associated message
with the test runner. A checkpoint includes the source file and line
number where the macro was invoked. If the test case is aborted unexpectedly,
the soruce location and message associated with the last registered
checkpoint is emitted into the log. Checkpoints can be used to identify
the location of an unexpected failure within a block of test case code.
The message is applied to an output stream
with operator<<
and can include other invocations of operator<<.
BOOST_TEST_MESSAGE(message)
writes the message into the test runner
log file.
BOOST_TEST_PASSPOINT() is similar to BOOST_TEST_CHECKPOINT,
but only registers a source file location with the test runner.
![]() |
Home | Libraries | People | FAQ | More |
![]() |
Home | Libraries | People | FAQ | More |
The test_case class represents a single test case. A
test case must be added to a test suite reachable from the master test
suite in order for the test runner to run the test case.
namespace boost { namespace unit_test { class BOOST_TEST_DECL test_case : public test_unit { public: enum { type = tut_case }; // Constructor test_case( const_string tc_name, callback0<> const& test_func ); // Access methods callback0<> const& test_func() const { return m_test_func; } }; } }
![]() |
Home | Libraries | People | FAQ | More |
The test_observer class encapsulates observers of test
execution. It provides a simple null style observer
behavior.
namespace boost { namespace unit_test { class BOOST_TEST_DECL test_observer { public: // test observer interface virtual void test_start( counter_t /* test_cases_amount */ ) {} virtual void test_finish() {} virtual void test_aborted() {} virtual void test_unit_start( test_unit const& ) {} virtual void test_unit_finish( test_unit const&, unsigned long /* elapsed */ ) {} virtual void test_unit_skipped( test_unit const& ) {} virtual void test_unit_aborted( test_unit const& ) {} virtual void assertion_result( bool /* passed */ ) {} virtual void exception_caught( execution_exception const& ) {} virtual int priority() { return 0; } }; } }
![]() |
Home | Libraries | People | FAQ | More |
The test_suite class represents a group of test cases
and suites in the test tree hierarchy.
namespace bosot { namespace unit_test { class BOOST_TEST_DECL test_suite : public test_unit { public: enum { type = tut_suite }; // Constructor explicit test_suite( const_string ts_name ); // test unit list management void add( test_unit* tu, counter_t expected_failures = 0, unsigned timeout = 0 ); void add( test_unit_generator const& gen, unsigned timeout = 0 ); void remove( test_unit_id id ); // access methods test_unit_id get( const_string tu_name ) const; std::size_t size() const { return m_members.size(); } }; } }
![]() |
Home | Libraries | People | FAQ | More |
The test_unit class forms the basis of the hierarchical
tree of test cases. Test applications will usually create instances of
test_case or test_suite, both of
which derive from test_unit.
namespace boost { namespace unit_test { class BOOST_TEST_DECL test_unit { public: enum { type = tut_any }; // Constructor test_unit( const_string tu_name, test_unit_type t ); // dependencies management void depends_on( test_unit* tu ); bool check_dependencies() const; // Public r/o properties typedef BOOST_READONLY_PROPERTY(test_unit_id,(framework_impl)) id_t; typedef BOOST_READONLY_PROPERTY(test_unit_id,(test_suite)) parent_id_t; readonly_property<test_unit_type> p_type; // type for this test unit readonly_property<const_string> p_type_name; // "case"/"suite" id_t p_id; // unique id for this test unit parent_id_t p_parent_id; // parent test suite id // Public r/w properties readwrite_property<std::string> p_name; // name for this test unit readwrite_property<unsigned> p_timeout; // timeout for the test unit execution readwrite_property<counter_t> p_expected_failures; // number of expected failures in this test unit mutable readwrite_property<bool> p_enabled; // enabled status for this unit void increase_exp_fail( unsigned num ); }; } }
![]() |
Home | Libraries | People | FAQ | More |
The unit_test_log_formatter class encapsulates formatting
of log events for an output stream.
namespace boost { namespace unit_test { class BOOST_TEST_DECL unit_test_log_formatter { public: enum log_entry_types { BOOST_UTL_ET_INFO, BOOST_UTL_ET_MESSAGE, BOOST_UTL_ET_WARNING, BOOST_UTL_ET_ERROR, BOOST_UTL_ET_FATAL_ERROR }; // Destructor virtual ~unit_test_log_formatter() {} // Formatter interface virtual void log_start( std::ostream&, counter_t test_cases_amount ) = 0; virtual void log_finish( std::ostream& ) = 0; virtual void log_build_info( std::ostream& ) = 0; virtual void test_unit_start( std::ostream&, test_unit const& tu ) = 0; virtual void test_unit_finish( std::ostream&, test_unit const& tu, unsigned long elapsed ) = 0; virtual void test_unit_skipped( std::ostream&, test_unit const& ) = 0; virtual void log_exception( std::ostream& os, log_checkpoint_data const& cd, execution_exception const& ex ) { // for backward compatibility log_exception( os, cd, ex.what() ); } virtual void log_exception( std::ostream&, log_checkpoint_data const&, const_string /* explanation */ ) {} virtual void log_entry_start( std::ostream&, log_entry_data const&, log_entry_types let ) = 0; virtual void log_entry_value( std::ostream&, const_string value ) = 0; virtual void log_entry_value( std::ostream&, lazy_ostream const& value ); // there is a default impl virtual void log_entry_finish( std::ostream& ) = 0; }; } }
![]() |
Home | Libraries | People | FAQ | More |
The unit_test_log_t class encapsulates the unit test
log. You obtain a reference to the single global unit test log instance
with the unit_test_log member.
namespace boost { namespace unit_test { namespace log { class BOOST_TEST_DECL unit_test_log_t : public test_observer, public singleton<unit_test_log_t> { public: // test_observer interface implementation void test_start( counter_t test_cases_amount ); void test_finish(); void test_aborted(); void test_unit_start( test_unit const& ); void test_unit_finish( test_unit const&, unsigned long elapsed ); void test_unit_skipped( test_unit const& ); void test_unit_aborted( test_unit const& ); void assertion_result( bool passed ); void exception_caught( execution_exception const& ); virtual int priority() { return 1; } // log configuration methods void set_stream( std::ostream& ); void set_threshold_level( log_level ); void set_format( output_format ); void set_formatter( unit_test_log_formatter* ); // test progress logging void set_checkpoint( const_string file, std::size_t line_num, const_string msg = const_string() ); // entry logging unit_test_log_t& operator<<( log::begin const& ); // begin entry unit_test_log_t& operator<<( log::end const& ); // end entry unit_test_log_t& operator<<( log_level ); // set entry level unit_test_log_t& operator<<( const_string ); // log entry value unit_test_log_t& operator<<( lazy_ostream const& ); // log entry value ut_detail::entry_value_collector operator()( log_level ); // initiate entry collection }; namespace { unit_test_log_t& unit_test_log; } } } }
![]() |
Home | Libraries | People | FAQ | More |
The unit_test_main function provides an implementation
of main that can be used by a test executable compiled
with BOOST_TEST_NO_MAIN.
namespace boost { namespace unit_test { int BOOST_TEST_DECL unit_test_main( init_unit_test_func init_func, int argc, char* argv[] ); } }
unit_test_main initializes the test framework, traverses
the test tree and reports the result as a the return value of the function.
Unexpected exceptions and system errors (signals, etc.) are caught and
mapped to appropriate return values by the function.
![]() |
Home | Libraries | People | FAQ | More |
Most of the time you will not need to interact with the classes in Boost.Test because the macro facilities for assertions, test cases and test suites hide all the details of the classes. If you are adapting legacy test code to Boost.Test you may need to interact with these classes in order to leverage existing test code without significant refactoring of the legacy test code.
The predicate_result
class is used to combine a boolean result from a predicate with a custom
failure message for reporting additional detail in the context of a failed
assertion. The test_unit,
test_case,
test_suite
and master_test_suite_t
classes provide the interface to test suites and their test cases for the
test runner. The test_observer,
unit_test_log_t
and unit_test_log_formatter
classes provide low-level interaction with the test runner log.
![]() |
Home | Libraries | People | FAQ | More |
The BOOST_AUTO_TEST_SUITE(name)
macro defines an automatically registered test suite named name
and opens a namespace named name.
A test suite can be nested within another test suite. Each test suite begun
with BOOST_AUTO_TEST_SUITE must be ended with BOOST_AUTO_TEST_SUITE_END
The new test suite is registered within its enclosing test suite, or the
master test suite if there is no enclosing test suite.
![]() |
Home | Libraries | People | FAQ | More |
The BOOST_AUTO_TEST_SUITE_END() macro ends the test
suite most recently defined with BOOST_AUTO_TEST_SUITE
or BOOST_FIXTURE_TEST_SUITE.
The corresponding namespace created when the test suite was defined is
closed by BOOST_AUTO_TEST_SUITE_END.
![]() |
Home | Libraries | People | FAQ | More |
The BOOST_FIXTURE_TEST_SUITE(suite,
fixture) macro begins the
test suite named suite and uses fixture
as a test fixture to be used as the base class of all test case classes
created in the suite with BOOST_AUTO_TEST_CASE.
![]() |
Home | Libraries | People | FAQ | More |
The BOOST_TEST_MODULE macro is used to define the name
of the master test suite. If BOOST_TEST_MODULE is defined,
it should be defined in exactly one source file. It can be defined to a
list of preprocessor tokens or a string literal. If a string literal is
used, surrounding quotation marks ("), will not
appear in the name of the master test suite.
#define BOOST_TEST_MAIN #define BOOST_TEST_MODULE "Assertions" #include <boost/test/unit_test.hpp>
![]() |
Home | Libraries | People | FAQ | More |
The BOOST_TEST_SUITE(name)
macro is used to create a new test suite named name.
The new suite must be added to the master test suite in order for any test
cases in the suite to be executed.
static test_suite* init_unit_test_suite(int argc, char* argv[]) { test_suite* hello_suite = BOOST_TEST_SUITE("hello"); register_function(*hello_suite); register_method_static_instance(*hello_suite); register_method_function_instance(*hello_suite); framework::master_test_suite().add(hello_suite); return 0; }
![]() |
Home | Libraries | People | FAQ | More |
A test suite is an ordered collection of test cases and other test suites. The test cases in a suite are executed in the order in which they are added to the suite. When test cases are automatically registered, they are added to the test suite in the order of their definition in the source file.
![]() |
Home | Libraries | People | FAQ | More |
BOOST_level_BITWISE_EQUALBOOST_level_CLOSEBOOST_level_CLOSE_FRACTIONBOOST_level_EQUALBOOST_level_EQUAL_COLLECTIONSBOOST_level_EXCEPTIONBOOST_FAILBOOST_level_GEBOOST_level_GTBOOST_level_LEBOOST_level_LTBOOST_level_MESSAGEBOOST_level_NEBOOST_level_NO_THROWBOOST_level_PREDICATEBOOST_level_SMALLBOOST_level_THROWBOOST_TEST_DONT_PRINT_LOG_VALUE![]() |
Home | Libraries | People | FAQ | More |
Suppose we wish to test that the following function, declared in hello.hpp
and supplied by a static library hello, inserted the text
Hello, world!\n to the given stream:
#if !defined(HELLO_HPP) #define HELLO_HPP #include <ostream> extern void hello_world(std::ostream& stream); #endif
We can accomplish this with the following test, saving it in test_hello.cpp:
#define BOOST_TEST_MAIN #include <boost/test/included/unit_test.hpp> #include "hello.hpp" #include <sstream> BOOST_AUTO_TEST_CASE(hello_world_inserts_text) { std::ostringstream dest; hello_world(dest); BOOST_REQUIRE_EQUAL("Hello, world!\n", dest.str()); }
We compile test_hello.cpp and link it against the static
library hello using the build environment for our platform
to produce an executable. No other source files or libraries are needed.
When we run the executable, it will execute our test case.
Suppose that our implementation of hello_world looks like
this:
#include "hello.hpp" void hello_world(std::ostream& stream) { }
When we run the unit test executable we obtain output similar to the following:[1]
Running 1 test case... src/tutorials/hello_test/1/test/test_hello.cpp(13): fatal error in "hello_world_inserts_text": critical check "Hello, world!\n" == dest.str() failed [Hello, world! != ] *** 1 failure detected in test suite "Master Test Suite" EXIT STATUS: 201
Oops, it looks like we forgot to implement hello_world!.
Let's fix that by changing hello.cpp to the following:
#include "hello.hpp" void hello_world(std::ostream& stream) { stream << "Hello, world!"; }
We can now rebuild our library, relink our unit test executable and re-run the test:
Running 1 test case... src/tutorials/hello_test/2/test/test_hello.cpp(13): fatal error in "hello_world_inserts_text": critical check "Hello, world!\n" == dest.str() failed [Hello, world! != Hello, world!] *** 1 failure detected in test suite "Master Test Suite" EXIT STATUS: 201
Oops, looks like we forgot to insert the newline character. Let's fix that
by changing hello.cpp to the following:
#include "hello.hpp" void hello_world(std::ostream& stream) { stream << "Hello, world!" << std::endl; }
We rebuild our library, relink our unit test executable again and re-run the test:
Running 1 test case... *** No errors detected EXIT STATUS: 0
Now all our tests are passing and we know that hello_world
does what we expect it to do. We used std::endl to insert
the newline character and it also flushes the output stream after inserting
the newline. If we didn't want the output stream to be flushed, we can change
hello_world to use a character literal:
#include "hello.hpp" void hello_world(std::ostream& stream) { stream << "Hello, world!\n"; }
We rebuild and re-run the test to verify that our change didn't break anything:
Running 1 test case... *** No errors detected EXIT STATUS: 0
Now that we've seen Boost.Test in action, let's take a closer look at what we have just done:
<boost/test/included/unit_test.hpp>.
We didn't link against any libraries or introduce any run-time dependencies.
main, but our
test executable linked and ran. Why? The preprocessor symbol BOOST_TEST_MAIN
instructed Boost.Test to supply an implementation of main
that executes all tests registered with the framework.
BOOST_AUTO_TEST_CASE
registered our unit test case with the framework and provides the necessary
preamble for the implementation of the testing function.
BOOST_AUTO_TEST_CASE
is the name of our test case and is a C++ identifier, not a string.
hello_world, the system under
test.
hello_world.
BOOST_REQUIRE_EQUAL.
[1]
The test runner output here is generated from the run-fail
rule in Boost.Build which includes the output from the executable and appends
the exit code of the process to the output.
![]() |
Home | Libraries | People | FAQ | More |
As we continue to add unit tests for a library, we can get quite a large number of tests. If they are true unit tests and each test exercises a single class isolated from its collaborators, then most of the tests are not relevant to the changes we are making. The test executable accepts a number of command-line arguments that allow us to control the behavior of the test framework, including which tests to run.
We can list the available tests in a test executable with --report_level
set to detailed:
> test_hello --report_level=detailed
Running 2 test cases...
Test suite "Master Test Suite" passed with:
2 assertions out of 2 passed
2 test cases out of 2 passed
Test case "hello_world_inserts_text" passed with:
1 assertion out of 1 passed
Test case "hello_world_stream_with_badbit_throws_runtime_error" passed with:
1 assertion out of 1 passed
![]() |
Caution |
|---|---|
The arguments to the test executable, such as |
Suppose we are continuing to make changes to hello_world
and we want to run only the tests that apply to that function. We can easily
identify the relevant tests in the output of --report_level
because we have used a test naming convention of prefixing all test case
names with the name of the system under test, hello_world.
Using the --run_test
argument, we can specify a comma-separated list of test case names to run:
> test_hello --run_test=hello_world_inserts_text,hello_world_stream_with_badbit_throws_runtime_error Running 2 test cases... *** No errors detected EXIT STATUS: 0
Wow, that's really a mouthfull! Even with command recall, typing this command
for the first time will require typing the exact names of all the test cases
for hello_world. As we add more test cases, we'll have
to extend the command line argument to account for each new test case.
We can solve this problem by using test suites, which organize tests into a named group:
struct hello_world_fixture { std::ostringstream dest; }; BOOST_AUTO_TEST_SUITE(test_hello); #define HELLO_WORLD_TEST_CASE(name_) \ BOOST_FIXTURE_TEST_CASE(hello_world_##name_, hello_world_fixture) HELLO_WORLD_TEST_CASE(inserts_text) { hello_world(dest); BOOST_REQUIRE_EQUAL("Hello, world!\n", dest.str()); } HELLO_WORLD_TEST_CASE(stream_with_badbit_throws_runtime_error) { dest.clear(std::ios_base::badbit); BOOST_REQUIRE_THROW(hello_world(dest), std::runtime_error); } BOOST_AUTO_TEST_SUITE_END();
Now --report_level
outputs the following:
> test_hello --report_level=detailed
Running 2 test cases...
Test suite "Master Test Suite" passed with:
2 assertions out of 2 passed
2 test cases out of 2 passed
Test suite "test_hello" passed with:
2 assertions out of 2 passed
2 test cases out of 2 passed
Test case "hello_world_inserts_text" passed with:
1 assertion out of 1 passed
Test case "hello_world_stream_with_badbit_throws_runtime_error" passed with:
1 assertion out of 1 passed
The indentation shows that the test cases for hello_world
are organized under the test suite named test_hello_world.
![]() |
Note |
|---|---|
We can't name the suite |
Now we can supply the name of the test suite to --run_test
to run all the test cases in the suite:
> test_hello --run_test=test_hello Running 2 test cases... *** No errors detected EXIT STATUS: 0
As we add more test cases to the suite, we don't have to change the command we are using to run the tests and we don't need to remember the exact names of the test cases.
Suites arrange test cases into a hierarchy. You can have suites within suites to provide larger groupings to test a collection of related classes together. Once a test case is part of a suite, we must use the name of the enclosing suite with the name of the test case if we wish to run a single test case within the suite by name:
> test_hello --run_test=test_hello/hello_world_inserts_text Running 1 test case... *** No errors detected
The names of the enclosing suites are separated from each other and from
the test case name with a slash (/). The names supplied
to --run_test
also allow for wildcard matching:
> test_hello --run_test=hello_world/*inserts_text Running 1 test case... *** No errors detected
Just as we can use a fixture with a test case to eliminate repeated setup and tear down, we can use a fixture with a test suite. All test cases in the test suite will derive from the test suite's fixture. If a test case in a test suite with a fixture specifies its own fixture, then the test case derives from the fixture specified on the test case and not on the test suite. If you want the test case to use both fixtures, then make your test case fixture derive from the test suite fixture.
We can use a test suite fixture for test_hello to take
care of the duplicated setup between test cases. Since our test cases are
now within the scope of a suite, we don't need to give them a unique prefix
anymore. Refactoring the tests to use a suite fixture and discarding the
prefix gives us the following code:
#define BOOST_TEST_MAIN #include <boost/test/included/unit_test.hpp> #include "hello.hpp" #include <ios> #include <sstream> struct hello_world_fixture { std::ostringstream dest; }; BOOST_FIXTURE_TEST_SUITE(test_hello, hello_world_fixture); BOOST_AUTO_TEST_CASE(inserts_text) { hello_world(dest); BOOST_REQUIRE_EQUAL("Hello, world!\n", dest.str()); } BOOST_AUTO_TEST_CASE(stream_with_badbit_throws_runtime_error) { dest.clear(std::ios_base::badbit); BOOST_REQUIRE_THROW(hello_world(dest), std::runtime_error); } BOOST_AUTO_TEST_SUITE_END();
Now --report_level
outputs the following:
> test_hello.exe --report_level=detailed
Running 2 test cases...
Test suite "Master Test Suite" passed with:
2 assertions out of 2 passed
2 test cases out of 2 passed
Test suite "test_hello" passed with:
2 assertions out of 2 passed
2 test cases out of 2 passed
Test case "inserts_text" passed with:
1 assertion out of 1 passed
Test case "stream_with_badbit_throws_runtime_error" passed with:
1 assertion out of 1 passed
![]() |
Home | Libraries | People | FAQ | More |
When we're testing a system, we want to test the failure cases as well as the success cases. This means forcing the system under test down an error path by orchestrating bad inputs or synthesizing errors from code collaborating with the system under test.
Let's add the requirement that hello_world
should throw the a std::runtime_error exception if the
supplied stream has the badbit set on the stream.
We can add a test case for this:
BOOST_AUTO_TEST_CASE(hello_world_stream_with_badbit_throws_runtime_error) { std::ostringstream dest; dest.clear(std::ios_base::badbit); hello_world(dest); BOOST_FAIL("std::runtime_error not thrown"); }
![]() |
Note |
|---|---|
The |
Instead of an assertion macro like BOOST_REQUIRE_EQUAL,
we're using the BOOST_FAIL
macro that guarantees test failure. If the call to hello_world
doesn't throw a runtime_error exception and continues
to the next line of code, then this test case fails:
Running 2 test cases... src/tutorials/testing_with_exceptions/1/test/test_hello.cpp(24): fatal error in "hello_world_stream_with_badbit_throws_runtime_error": std::runtime_error not thrown *** 1 failure detected in test suite "Master Test Suite" EXIT STATUS: 201
Now let's enhance the implementation to support this requirement:
void hello_world(std::ostream& stream) { if (stream.bad()) { throw std::runtime_error("bad stream"); } stream << "Hello, world!\n"; }
We run our test and get something similar to the following:
Running 2 test cases... unknown location(0): fatal error in "hello_world_stream_with_badbit_throws_runtime_error": std::runtime_error: bad stream src/tutorials/testing_with_exceptions/2/test/test_hello.cpp(13): last checkpoint *** 1 failure detected in test suite "Master Test Suite" EXIT STATUS: 201
Now the test is still failing, so what did we do wrong? The exception from
our system under test unwound the call stack back into the unit test framework,
which caught the exception and reported this as a failure. We need to tell
the test framework that an exception is expected in this situation. We can
use BOOST_REQUIRE_THROW
to tell the test framework that an expression is expected to throw a particular
type of exception. If the exception isn't thrown or an exception of a different
type is thrown, then the test fails. Our test now looks like this:
BOOST_AUTO_TEST_CASE(hello_world_stream_with_badbit_throws_runtime_error) { std::ostringstream dest; dest.clear(std::ios_base::badbit); BOOST_REQUIRE_THROW(hello_world(dest), std::runtime_error); }
Now our test case is passing:
Running 2 test cases... *** No errors detected EXIT STATUS: 0
test_hello.cpp, which is including the entire
unit test framework source. This leads to a lengthy compile every time
we have to change the tests.
![]() |
Home | Libraries | People | FAQ | More |
When we added our second test case in the previous
tutorial, we ended up with some duplicated setup between the two test
cases. This is a common occurrence in unit testing. We have some prerequisites
for the system under test that must be prepared in order to exercise the
system. In our case, it is a single output string stream that we use for
capturing the output of our hello_world function.
Boost.Test provides a facility called a fixture for encapsulating repeated setup and tear down code between test cases. In our example, there isn't any explicit tear down code because the output string streams are created on the stack and destroyed when execution exits the test case. We have a little bit of repeated setup code that we can move to a fixture that is used by both our test cases. Let's put that repeated code in a fixture:
struct hello_world_fixture { hello_world_fixture() : dest() { } ~hello_world_fixture() { } std::ostringstream dest; }; BOOST_FIXTURE_TEST_CASE(hello_world_inserts_text, hello_world_fixture) { hello_world(dest); BOOST_REQUIRE_EQUAL("Hello, world!\n", dest.str()); } BOOST_FIXTURE_TEST_CASE(hello_world_stream_with_badbit_throws_runtime_error, hello_world_fixture) { dest.clear(std::ios_base::badbit); BOOST_REQUIRE_THROW(hello_world(dest), std::runtime_error); }
A fixture is simply a class or struct that is inherited by the test case.
We connect the test case to the fixture by using BOOST_FIXTURE_TEST_CASE
instead of BOOST_AUTO_TEST_CASE.
The latter simply connects each test case to an empty fixture. After refactoring
the test cases to use a fixture, we run the tests to make sure the tests
still pass.
When using a fixture, the order of construction and destruction is as follows when a test case is executed:
This process happens for each test case that is executed, ensuring that each test case has a fresh fixture and remains independent of other test cases.
In most cases, the setup will be a little more involved than just creating an instance variable and there will be some work done in the constructor of the fixture. We could simply use the default constructor and destructor of our fixture in this case. We've written the constructor and destructor explicitly to emphasize that this is where setup and tear down occur.
Now that we've transformed the test cases to use a fixture, it seems we've simply traded one piece of repetition, the construction of the output string stream, for another: the repeated use of the fixture name and system under test in our test cases. We can use a custom test case macro to get rid of this duplication:
struct hello_world_fixture { std::ostringstream dest; }; #define HELLO_WORLD_TEST_CASE(name_) \ BOOST_FIXTURE_TEST_CASE(hello_world_##name_, hello_world_fixture) HELLO_WORLD_TEST_CASE(inserts_text) { hello_world(dest); BOOST_REQUIRE_EQUAL("Hello, world!\n", dest.str()); } HELLO_WORLD_TEST_CASE(stream_with_badbit_throws_runtime_error) { dest.clear(std::ios_base::badbit); BOOST_REQUIRE_THROW(hello_world(dest), std::runtime_error); }
Every test case has to have a unique name within the scope of its declaration,
either the global namespace or a custom namespace, which is why we've been
prefixing our test case names with the name of the system under test, hello_world.
Once we accumulate a few tests, the chances for a clash between test names
increases.
With our custom test case macro, we reduce the chance for a test case name
clash by ensuring that every test case name is prefixed by the name of the
system under test. We ensure that every test case for hello_world
uses the same fixture and we gain some readability of the test cases by eliminating
the distracting repetition. If we change the name of the fixture, then we
need only edit the custom test case macro that supplies the fixture name.
In the next tutorial, we'll see an alternative way of eliminating this duplication of the prefixes of test case names.
![]() |
Home | Libraries | People | FAQ | More |
These tutorials will get you started using Boost.Test. They are intended to be read in order and proceed from the basics of writing your first test to running selected tests. Once you've finished with the tutorials, you may want to read about test case design for some suggestions on testing various situations in C++. The full details of the framework are provided in the reference section.