0

互いに呼び出す関数がたくさんあるとします。それぞれを個別にテストしたいと思います。たとえば、Bar が正しくなくても、実装されていなくても Foo をテストできるはずです。1 つの解決策は、これらの関数を仮想メソッド (C++ を使用していない場合は通常のメソッド) に変換することです。例えば

class K {
 public:
  virtual int Foo();
  virtual int Bar();   // called by Foo

  // No member variables.
};

これで、テストでこれを行うことができます:

// You could use googlemock instead of this.
class KFoo : public K {
 public:
  virtual int Bar() {
    return 42;
  }
};

// googletest
TEST(K, Foo) {
  std::unique_ptr<K> k(new KFoo);
  assert(k->Foo() == 7);  // Bar gets called, and returns 42.
}

ただし、これはいくつかの理由で奇妙です。

  1. K にはメンバー変数がありません。それは「ステートレス」です。
  2. new K何かを呼び出すために必要です。

これは良い考えですか?これってもう名前あるの?明らかに、仮想化は物事を遅くしますが、IIUC では、大量の呼び出しを行わない限り、パフォーマンスへの影響は小さいです (そして、時期尚早の最適化について彼らが何を言っているか知っています)。これが保守性、テスト容易性などにどのように影響するかについて、私はもっと興味があります。

4

1 に答える 1

1

C++ については確信が持てませんが、C# (完全な OOP) の経験があります。

C#では、上記の設計は抽象クラス/継承だと思います。私が間違っていなければ、C++ での設計は C# では次のようになります。

public class K{
    public virtual int Foo(){
        return Bar();
    }
    public virtual int Bar(){
        // actual code
    }
}

public class KFoo : K{
    public override int Bar(){
        return 42;
    }
}

このような設計は OOP の基本であるため、害はありません。ただし、継承が追加されると、より複雑になります (K2 は K を継承し、K3 は K2 を継承するなど)。追加情報として、なぜ継承/クラスベースのメソッドがあなたが思っているほどモジュール化されていないのかについての私の見解を説明するこの回答を読むことができます。

IMHO、継承を定義する代わりに「サービス」クラスを注入すると、モジュールになります。これは、継承よりも合成と呼ばれます。

public class KBarService : IKBarService{
    public int Bar(){
        // actual code
    }
}
public class KBarServiceMock : IKBarService{
    public int Bar(){
        return 42;
    }
}
public class K{
    public K(IKBarService service){
        this.service = service;
    }
    IKBarService service;

    public int Foo(){
        return Bar();
    }
    public int Bar(){
        return service.Bar();
    }
}

に対しても同じことができますFoo()。この設計によりKBarService、他のクラスで を再利用できます。そのクラスが K の派生クラスではない場合でも同様です。

于 2013-07-15T01:58:08.877 に答える