2

私は TDD と C を試しています。TDD アプローチに従って単純な malloc ラッパーを書きたいと思っています。ボブ・マーティンの TDD の 3 つの法則に従おうとしています。

  1. 失敗した単体テストに合格するためでない限り、製品コードを記述しないでください。
  2. 失敗するのに十分な量以上の単体テストを作成しないでください。ビルドの失敗は失敗です。
  3. 失敗した 1 つの単体テストに合格するのに十分な数以上の製品コードを記述しないでください。

これは今までの私のコードです:

    J_STATUS MemAlloc(long Size, void **OutPtr) {
        J_STATUS ReturnStatus;
        void *Ptr;

        Ptr = NULL;

        if (Size >= 0) {
            Ptr = malloc(Size);
            *OutPtr = Ptr;
            ReturnStatus = SUCCESS;
            //TODO controllare malloc error
        } else {
            ReturnStatus = ERROR;
        }
        return ReturnStatus;
    }

そして、これらは私のテストです(私はUnityテストフレームワークを使用しています):

    #include "../unity/unity.h"
    #include "../src/jMem.h"
    #include "stdlib.h"

    static int *ptr;
    static J_STATUS Result;
    static long Size;
    static long Count;

    void setUp() {
        ptr = NULL;
        Size = 10;
        Count = 5;
    }

    void tearDown() {
        if (ptr != NULL) {
            free(ptr);
        }
    }

    void test_MemAllocShouldAllocateMemoryAndReturnSuccess(void) {
        Result = MemAlloc(Size, (void **) &ptr);
        TEST_ASSERT_EQUAL(SUCCESS, Result);
        TEST_ASSERT_NOT_NULL(ptr);

    }

    void test_MemAllocShouldReturnErrorIfSizeIsNegative(void) {
        Size = -4;

        Result = MemAlloc(Size, (void **) &ptr);

        TEST_ASSERT_EQUAL(ERROR, Result);
    }

失敗した malloc のテストをどのように作成すればよいでしょうか。異なるバージョンの malloc をリンクしたり、malloc を失敗させるマクロを記述したりできることはわかっていますが、これはこのテストにのみ当てはまり、他のテストでは実際の malloc を使用したいと考えています。

何か案が?ありがとうございました

4

4 に答える 4

1

代わりmalloc()に、次のような関数ポインタを使用できます。

void* (*pMalloc)(size_t size)

そして、pMalloc(some size)の代わりにを使用しますmalloc(some size)

malloc()のように、を指すようにポインタを設定するとpMalloc = &malloc;、実際のを使用することになりますmalloc()。自分の関数を指すように設定すると、自分の関数を使用することになります。

malloc()関数では、を返すことで障害をシミュレートできますNULLmalloc()テストに必要な場合は、そこから呼び出すこともできます。

同様に、独自のを置き換えることができますfree()

これらの置換された関数では、何が起こっているかをログに記録できます。

たとえば、LONG_MAXラッパー関数に渡すと(long引数としてサイズを使用していると思います)、偽物malloc()は実際に受け取ったサイズをログに記録できます。テストではLONG_MAX、がラッパーからmalloc()asに伝播したことに気付くことができます。また、(ビット数の点で)より短い(size_t)LONG_MAX場合は、値()を比較することで不一致を検出できます。size_tlongLONG_MAX != (size_t)LONG_MAX

また、偽物が(それ自体の内部から)返すポインター値をログに記録しmalloc()、ラッパーによって返される値と比較して、これらが異なるかどうかを確認することもできます。

アイデアをさらに詳しく説明して、さらに多くのテストを考え出すことができます(たとえば、ラッパーはNULL以外の値を返しますが、偽物malloc()(したがって実際の値)はまったく呼び出されません)。

これをすべて実行している間、ファイルまたはにログを記録する必要はありませんstdout。その目的のためにデータ構造を専用にして、それを調べることができます。

于 2012-09-21T02:35:27.583 に答える
1

たぶん、それはテストする必要のないエッジケースです。コードを書くだけです。:-)

一方、良い TDD を実践したいのであれば、malloc 呼び出しを関数パラメーターに昇格させるという別のオプションもあります。関数ポインターとして、malloc1 つのテストで通常のアドレスを渡しmalloc_that_errors、エラー テスト ケースでのアドレスを渡すことができます。

個人的には好きではないラッパーのインターフェースを汚すことに注意してください。それはあなたが目指している抽象化を壊し、私はmallocどこにでも行きたくない. それを考えると、私はそれをテストしないことに戻ります。:-D

それが役立つことを願っています!

ブランドン

于 2012-09-21T00:53:41.053 に答える
0

古い質問ですが、コンパイラによっては、答えが1つ足りないと感じています。GNU LD には、--wrap symbolリンク時に特定の機能をオーバーライドできるオプションがあります。

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

このコードと同様に、 へのすべての呼び出しは へmallocの呼び出しに置き換えられます。__wrap_malloc実際の malloc を呼び出したい場合は、 から利用できます__real_malloc

この機能は他のリンカーでも利用できるかもしれませんが、GCC の場合は良い代替手段です。

于 2015-10-07T06:08:13.247 に答える
0

サイズ引数ではlongなく使用する場合、mallocラッパーはあまり説得力がありません。size_t

非常に大量のメモリを割り当て、使用size_tして最大値を見つけることで失敗させることができるはずです。ほとんどの realmalloc()はその割り当てに成功しないため、失敗します。

もちろん、これはまだ失敗するかなり偽の方法です。適切な唯一の方法は、フックを提供して別のmalloc().

于 2012-09-20T10:11:45.227 に答える