44

と呼ばれる C++ クラスで (Boost 単体テスト フレームワークを使用して) 単体テストを実行しようとしていますVariableImpl。詳細はこちら。

class Variable
{
public:
  void UpdateStatistics (void) {
    // compute mean based on m_val and update m_mean;
    OtherClass::SendData (m_mean);
    m_val.clear ();
  }
  virtual void RecordData (double) = 0;

protected:
  std::vector<double> m_val;

private:
  double m_mean;
};

class VariableImpl : public Variable
{
public:
  virtual void RecordData (double d) {
    // put data in m_val
  }
};

私の質問は、平均が正しく計算されていることを確認するにはどうすればよいですか? m_mean1)は保護され、2)UpdateStatistics別のクラスのメソッドを呼び出してからベクトルをクリアすることに注意してください。

私が見ることができる唯一の方法は、ゲッター (たとえば、GetMean) を追加することですが、私はこの解決策がまったく好きではなく、最もエレガントだとも思いません。

どうすればいいですか?

また、プライベート変数ではなくプライベート メソッドをテストする場合はどうすればよいでしょうか?

4

8 に答える 8

62

ユニットテストはユニットをテストする必要あり、理想的にはすべてのクラスが自己完結型のユニットです。これは、単一責任の原則から直接導かれます。

したがって、クラスのプライベート メンバーをテストする必要はありません。クラスは、単体テストでそのままカバーできるブラック ボックスです。

一方、これは常に正しいとは限らず、場合によっては正当な理由があります (たとえば、クラスのいくつかのメソッドが、テストする必要があるプライベート ユーティリティ関数に依存している可能性があります)。非常に単純で非常に粗雑ですが、最終的に成功する解決策の 1 つは、クラスを定義するヘッダーを含めるに、以下を単体テスト ファイルに入れることです。

#define private public

もちろん、これはカプセル化を破壊し、です。しかし、テストのために、それは目的を果たします。

于 2011-07-21T15:36:31.723 に答える
14

保護されたメソッド/変数の場合、クラスから Test クラスを継承し、テストを行います。

プライベートの場合はフレンドクラスを紹介。それは最善の解決策ではありませんが、あなたのために仕事をすることができます.

またはこのハック

#define private public
于 2011-07-21T15:28:51.780 に答える
8

一般的に、ここで他の人が言ったことに同意します-パブリックインターフェイスのみを単体テストする必要があります。それにもかかわらず、特定のテスト ケースの準備をするために、保護されたメソッドを最初に呼び出さなければならないケースがありました。私は最初に#define protected public上記のアプローチを試みました。これは Linux/gcc では機能しましたが、Windows/VisualStudio では失敗しました。その理由は、 に変更protectedするとpublicマングルされたシンボル名も変更され、リンカ エラーが発生したためです。ライブラリは保護され __declspec(dllexport) void Foo::bar()たメソッドを提供しましたが、その#define場で、テスト プログラムは未解決のシンボル エラーを発生させるパブリックメソッドを予期していました。 __declspec(dllimport) void Foo::bar()

このためfriend、クラスヘッダーで次のことを行うベースのソリューションに切り替えました。

// This goes in Foo.h
namespace unit_test {   // Name this anything you like
struct FooTester; // Forward declaration for befriending
}

// Class to be tested
class Foo 
{
  ...
private:
  bool somePrivateMethod(int bar);
  // Unit test access
  friend struct ::unit_test::FooTester;
};

そして、私の実際のテストケースでは、これを行いました:

#include <Foo.h>
#include <boost/test/unit_test.hpp>
namespace unit_test {
// Static wrappers for private/protected methods
struct FooTester
{
  static bool somePrivateMethod(Foo& foo, int bar)
  {
    return foo.somePrivateMethod(bar);
  }
};
}

BOOST_AUTO_TEST_SUITE(FooTest);
BOOST_AUTO_TEST_CASE(TestSomePrivateMethod)
{
  // Just a silly example
  Foo foo;
  BOOST_CHECK_EQUAL(unit_test::FooTester::somePrivateMethod(foo, 42), true);
}
BOOST_AUTO_TEST_SUITE_END();

これは、Linux/gcc および Windows/VisualStudio で動作します。

于 2014-04-24T11:16:34.827 に答える
4

c++ で保護されたデータをテストする良い方法は、フレンド プロキシ クラスの割り当てです。

#define FRIEND_TEST(test_case_name, test_name)\
friend class test_case_name##_##test_name##_Test

class MyClass 
{
private:
  int MyMethod();
  FRIEND_TEST(MyClassTest, MyMethod);
};

class MyClassTest : public testing::Test 
{
public:
  // ...
  void Test1()
  {
    MyClass obj1;
    ASSERT_TRUE(obj1.MyMethod() == 0);
  }

  void Test2()
  {
    ASSERT_TRUE(obj2.MyMethod() == 0);
  }

  MyClass obj2;
};

TEST_F(MyClassTest, PrivateTests) 
{
 Test1();
 Test2(); 
}

goolge テスト (gtest) をもっと見る: http://code.google.com/p/googletest-translations/

于 2012-10-30T11:56:43.190 に答える
1

動作が保証されている場合はVariableも同様であるように、VariableImplを単体テストします。

内部のテストは世界で最悪のことではありませんが、インターフェースの契約が保証されている限り、内部のテストは何でも可能であることが目標です。それがVariableをテストするための奇妙なモック実装の束を作成することを意味する場合、それは合理的です。

それが多くのように思われる場合は、実装の継承によって関心の分離が大きくなることはないと考えてください。単体テストが難しい場合、それは私にとってかなり明白なコードの臭いです。

于 2011-07-21T15:34:13.573 に答える
0

一般に、プライベート/保護された実装ではなく、クラスのパブリック インターフェイスをテストすることをお勧めします。この場合、パブリック メソッドによって外の世界から観察できない場合は、単体テストでテストする必要がない場合があります。

機能に子クラスが必要な場合は、実際の派生クラスを単体テストするか、適切な実装を持つ独自のテスト派生クラスを作成します。

于 2011-07-21T15:36:15.570 に答える
0

Google テスト フレームワークの例:

// foo.h
#include "gtest/gtest_prod.h"
class Foo {
  ...
 private:
  FRIEND_TEST(FooTest, BarReturnsZeroOnNull);
  int Bar(void* x);
};

// foo_test.cc
...
TEST(FooTest, BarReturnsZeroOnNull) {
  Foo foo;
  EXPECT_EQ(0, foo.Bar(NULL));
  // Uses Foo's private member Bar().
}

主なアイデアは、friend cpp キーワードの使用です。この例を次のように拡張できます。

// foo.h
#ifdef TEST_FOO
#include "gtest/gtest_prod.h"
#endif

class Foo {
  ...
 private:
  #ifdef TEST_FOO
  FRIEND_TEST(FooTest, BarReturnsZeroOnNull);
  #endif
  int Bar(void* x);
};

TEST_FOO プリプロセッサは、次の 2 つの方法で定義できます。

1) CMakeLists.txt 内

option(TEST "Run test ?" ON)
if (TEST)
  add_definitions(-DTEST_FOO)
endif()

2)コンパイラへの引数として

g++ -D TEST $your_args
于 2014-10-14T13:25:25.317 に答える