11

私の問題が何であるかが明確になるように、私はこの本当に些細なクラスを書きました:

class A
{
public:
    int x;
    A(int y) {x=y;}
    bool operator==(const A &other) const {return x==other.x;}
};

ここで、A first(1) と A second(1) を定義すると、BOOST_CHECK_EQUAL(first, second) がパスするのが自然に思えます。ただし、これを実行しようとすると 50 個のエラーが発生しました。最初のエラーは次のように聞こえます: no math for operator << in ostr << t これはブースト コードのどこかにあります... 他のテストは問題なく動作し、既知の型を比較したり、ポインターとは異なりますが、クラス オブジェクトで発生するように見える何かが異なります。

4

4 に答える 4

27

の問題を解決するために私が特定した 3 つの方法がありますoperator<<

最初の方法はoperator<<、タイプに を提供することです。これが必要なのは、失敗した場合、オブジェクトboost_check_equalを呼び出して失敗もログに記録するためです。operator<<これが実際にどのように達成されるかを確認するには、休憩の後の詳細な補遺を参照してください。見た目よりも難しいです。

2 番目の方法は、先ほど述べたロギングを行わないことです。#definineingでこれを行うことができますBOOST_TEST_DONT_PRINT_LOG_VALUE。1 つのテストだけのロギングを無効にするには、問題のテストを this で囲み、#defineすぐ#undefに次のようにします。

#define BOOST_TEST_DONT_PRINT_LOG_VALUE
BOOST_CHECK_EQUAL (first, second);
#undef BOOST_TEST_DONT_PRINT_LOG_VALUE

operator<<3 番目の方法は、ある項目を別の項目と比較するのではなく、bool をチェックするだけで、型で動作する の必要性を回避することです。

BOOST_CHECK (first == second);

ご希望の方法をお選びください。


私の好みは最初ですが、それを実装するのは驚くほど困難です。グローバル スコープで定義するだけoperator<<では機能しません。名前解決の問題が原因だと思います。これを修正するための一般的な提案の 1 つは、名前空間に を配置することoperator<<ですstd。これは、少なくとも一部のコンパイラでは実際に機能しますが、標準ではstd名前空間に何かを追加することを禁止しているため、好きではありません。

私が見つけたより良い方法は、型のカスタムprint_log_valueクラス テンプレートの特殊化を実装することです。 print_log_valueBoost.Test の内部で使用されるクラス テンプレートoperator<<で、指定された型の正しいものを実際に呼び出します。operator<<重いものを持ち上げるために委任します。カスタム タイプの特殊化print_log_valueは、Boost [要出典] によって公式にサポートされており、このようにして達成されます。

あなたのタイプが呼び出されたと仮定するとTimestamp(それは私のコードにあります)、最初にグローバルな free operator<<for を定義しますTimestamp

static inline std::ostream& operator<< (std::ostream& os, const Mdi::Timestamp& ts)
{
    os << "Timestamp";
    return os;
}   

...そして、定義したばかりprint_log_valueに委譲して、その専門化を提供します。operator<<

namespace boost { namespace test_tools {
template<>           
struct print_log_value<Mdi::Timestamp > {
void operator()( std::ostream& os,
    Mdi::Timestamp const& ts)
{
    ::operator<<(os,ts);
}
};                                                          
}}
于 2013-07-10T14:22:39.687 に答える
4

これは、John Dibling からの優れた回答の補足です。問題は、正しい名前空間に出力演算子が必要なことにあるようです。したがって、グローバル出力が定義されている場合は、グローバル オペレーターに転送する名前空間でoperator<<別の出力を定義することにより、このエラーを回避できます (少なくとも Visual Studio 2015、別名 vc14、および boost 1.60 を使用) 。このマイナーな調整により、奇妙で冗長なクラスboost::test_tools::tt_detailの特殊化を避けることができます。print_log_valueこれが私がしたことです:

namespace boost {
namespace test_tools {
namespace tt_detail {
std::ostream& operator<<(std::ostream& os, Mdi::Timestamp const& ts)
{
    return ::operator<<(os, ts);
}
}  // namespace tt_detail
}  // namespace test_tools
}  // namespace boost

この質問と回答が投稿されてから 3 年が経ちましたが、Boost.Test のドキュメントで明確に議論されているのを見たことがありません。

于 2016-11-22T16:36:43.127 に答える
4

John Diblingの回答に基づいて、整数値を 10 進数ではなく 16 進数でダンプする方法を探していましたが、このアプローチを思いつきました。

// test_macros.h in my project
namespace myproject
{
namespace test
{
namespace macros
{
    extern bool hex;

    // context manager
    struct use_hex
    {
        use_hex()  { hex = true; }
        ~use_hex() { hex = false; }
    };

 }; // namespace
 }; // namespace
 }; // namespace

namespace boost
{
namespace test_tools
{

    // boost 1.56+ uses these methods

    template<>
    inline                                               
    void                                                 
    print_log_value<uint64>::                       
    operator()(std::ostream & out, const uint64 & t) 
    {                                                    
        if(myproject::test::macros::hex)                    
            out << ::boost::format("0x%016X") % t;           
        else 
            out << t;                                        
    }                                                    

namespace tt_detail
{

    // Boost < 1.56 uses these methods

    template <>
    inline
    std::ostream &
    operator<<(std::ostream & ostr, print_helper_t<uint64> const & ph )
    {
        if(myproject::test::macros::hex)
            return ostr << ::boost::format("0x%016X") % ph.m_t;

        return ostr << ph.m_t;
    }

}; // namespace
}; // namespace
}; // namespace

単体テスト ケースでは、グローバルな静的ブール値を設定することで 16 進数のオン/オフを切り替えることができます。次に例を示します。

for(uint64 i = 1; i <= 256/64; ++i)
{
    if(i % 2 == 0) test::macros::hex = true;
    else           test::macros::hex = false;
    BOOST_CHECK_EQUAL(i+1, dst.pop());
}

そして、私が探していた動作を取得します:

test_foobar.cc(106): error in "test_foobar_51": check i+1 == dst.pop() failed [2 != 257]
test_foobar.cc(106): error in "test_foobar_51": check i+1 == dst.pop() failed [0x0000000000000003 != 0x0000000000000102]
test_foobar.cc(106): error in "test_foobar_51": check i+1 == dst.pop() failed [4 != 259]
test_foobar.cc(106): error in "test_foobar_51": check i+1 == dst.pop() failed [0x0000000000000005 != 0x0000000000000104]

または、コンテキスト マネージャーを使用できます。

{
    test::macros::use_hex context;

    for(uint64 i = 1; i <= 4; ++i)
    {
        BOOST_CHECK_EQUAL(i + 0x200, i + 0x100);
    }
}

for(uint64 i = 1; i <= 4; ++i)
{
    BOOST_CHECK_EQUAL(i + 0x200, i + 0x100);
}

そして、16 進出力はそのブロックでのみ使用されます。

test_foobar.cc(94): error in "test_foobar_28": check i + 0x200 == i + 0x100 failed [0x0000000000000201 != 0x0000000000000101]
test_foobar.cc(94): error in "test_foobar_28": check i + 0x200 == i + 0x100 failed [0x0000000000000202 != 0x0000000000000102]
test_foobar.cc(94): error in "test_foobar_28": check i + 0x200 == i + 0x100 failed [0x0000000000000203 != 0x0000000000000103]
test_foobar.cc(94): error in "test_foobar_28": check i + 0x200 == i + 0x100 failed [0x0000000000000204 != 0x0000000000000104]
test_foobar.cc(100): error in "test_foobar_28": check i + 0x200 == i + 0x100 failed [513 != 257]
test_foobar.cc(100): error in "test_foobar_28": check i + 0x200 == i + 0x100 failed [514 != 258]
test_foobar.cc(100): error in "test_foobar_28": check i + 0x200 == i + 0x100 failed [515 != 259]
test_foobar.cc(100): error in "test_foobar_28": check i + 0x200 == i + 0x100 failed [516 != 260]
于 2014-02-21T22:03:20.097 に答える
3

Boost 1.64 を起動して、カスタマイズ ポイントを介してユーザー定義型を記録するクリーンな方法があります。この機能の完全なドキュメントは、ここにあります。

ドキュメントの例を以下に示します。アイデアは、出力しboost_test_print_typeたいタイプの関数を定義し、この関数をテスト ケース (ADL で見つけたもの) に入れることです。

#define BOOST_TEST_MODULE logger-customization-point
#include <boost/test/included/unit_test.hpp>

namespace user_defined_namespace {
  struct user_defined_type {
      int value;

      user_defined_type(int value_) : value(value_)
      {}

      bool operator==(int right) const {
          return right == value;
      }
  };
}

namespace user_defined_namespace {
  std::ostream& boost_test_print_type(std::ostream& ostr, user_defined_type const& right) {
      ostr << "** value of user_defined_type is " << right.value << " **";
      return ostr;
  }
}

BOOST_AUTO_TEST_CASE(test1)
{
    user_defined_namespace::user_defined_type t(10);
    BOOST_TEST(t == 11);

    using namespace user_defined_namespace;
    user_defined_type t2(11);
    BOOST_TEST(t2 == 11);
}
于 2017-06-28T19:18:00.343 に答える