3

現在、社内で単体テストを導入し、システムコールをモックする最善の方法を考えています。

次のコードを検討してください

    int fd = open(path, O_RDONLY);
    if (fd < 0) {
        LOG.error() << "cannot load plugin " << path << std::endl;
        return ERROR(ERROR_OPENING_PLUGING);
    }
    // do other stuff

明らかに、 openのシステム コールをモックする必要があります。

これを行うには、次の方法を見つけました。

  1. 正しい - デザインに関しては醜い方法です。インターフェイスと実装を作成する

    class ISystem
    {
    public:
        typedef std::auto_ptr<ISystem> Ptr;
    
        ISystem() {};
        virtual ~ISystem() {};
    
        virtual int open(const char* file, int path) = 0;
    };
    
    class System : public ISystem
    {
    public:
        System() {};
        virtual ~System() {};
    
        virtual int open(const char* file, int path);
    
        static ISystem::Ptr Get();
    };
    

そしてそれを使う

    Common::Error dlopen_signed(ISystem::Ptr& system, const char* path, int flags, void*& ret)
    {
    int fd = system->open(path, O_RDONLY);
    if (fd < 0) {
        LOG.error() << "cannot load plugin " << path << std::endl;
        return ERROR(ERROR_OPENING_PLUGING);
    }
    char fd_path[32];

すべての関数にはもう 1 つの引数 (ISystem::Ptr& システム) が必要なので、これは好きではありません。これは、すべての製品コードで同じです。

また、速度についても不明です(これには、非常に高速でなければならない基本的なシステムコールの追加レイヤーが含まれます)

2) リンク シームを使用する リンカーは、システム バージョンよりもユーザー バージョンの関数を優先するように設計されています。

しかし、これは一部のシステム コール (open など) では機能せず (理由がわからない)、このソリューションは少しハック的です。

3) --wrap コンパイラ機能を使用する

--wrap symbol シンボルのラッパー関数を使用します。シンボルへの未定義の参照は、__wrap_symbol に解決されます。__real_symbol への未定義の参照は、symbol に解決されます。これは、システム関数のラッパーを提供するために使用できます。ラッパー関数は __wrap_symbol という名前にする必要があります。システム関数を呼び出したい場合は、__real_symbol を呼び出す必要があります。以下は簡単な例です。

void *
__wrap_malloc (int c)
{
  printf ("malloc called with %ld\n", c);
  return __real_malloc (c);
} 

この解決策は素晴らしいですが、私が推測するすべてのコンパイラで機能するとは限りません。

問題は、プロジェクトでどちらを使用していますか?

4

3 に答える 3

2

何をモックし、何を単体テストするかを線引きする必要があります。単体テストを 100% カバーすることは、最終的な目標ではありません。

システム呼び出しを本当にモックしたい場合は、それらをラッパーに入れるのが最善です(問題の最初のオプション)。1 つの巨大なラッパーではなく、機能ごとに複数のラッパーに分割する必要があります。

于 2013-11-05T09:23:59.300 に答える
-1

(1)モックについての例は正しくありません。おそらく、何をしているのかを明確にしたくないためであり、例では何が何をモックするのかを示していません。モッキングは、実際にはポリモーフィズムの実用的な使用例です。人々はすべてのものをラッパー関数でラップし、さらにラッパークラスでラップする傾向があります

IParam param=new ParamMock(xxx);
File file(param); // mocked
....
file.open(xxx)

(2) 私はそれについて知りません

(3) それは間違いなく、あなたがあまりにも多くの知識を持ち、単体テストに多大な労力を費やしていることを示しています。結局、ユニットテストは捨てられることを常に念頭に置いています。どのような開発プロセスに従っていますか?

于 2013-11-05T09:47:42.347 に答える