モック・スタブをインジェクトできるカスタマイズポイントを作ってテストを簡単にしたい


通信やDBなど外部リソースにアクセスする処理をスタブに置き換えることで、単体テストを簡単に書くことができます。

そのためにはひとつのクラスであれもこれもやるのではなく、役割ごとにクラスを分割しておくと便利ですね。

実際にどんな実装手段があるのか考えてみました。

いいとかわるいとかは考えず、思いつく方法をたくさん挙げてみたいと思います。


テンプレートパラメーターとして渡す
=====


```cpp
template <
    typename NetworkService,
    typename DatabaseService
>
class business_logic
{
public:
    void someLogic() {
        NetworkService::someLogic();
        DatabaseService::someLogic();
    }
};
```

使うときはこんな感じ

```cpp
business_logic<my_network_service, my_database_service> logic;
logic.someLogic();
```

テストの時はこんな感じ

```cpp
business_logic<stub_network_service, stub_database_service> stub_logic;
stub_logic.someLogic();
```

いろいろ亜種が考えられます。

* 継承を利用するとか

```cpp
template <
    typename NetworkService,
    typename DatabaseService
>
class business_logic : NetworkService, DatabaseService
{
public:
    void some_logic() {
        NetworkService::some_logic();
        DatabaseService::some_logic();
    }
};
```

* オブジェクトも渡すとか

```cpp
template <
    typename NetworkService,
    typename DatabaseService
>
class business_logic
{
public:
    void business_logic(NetworkService const& network_service, DatabaseService const& database_service)
    :   network_service_(network_service)
    ,   database_service_(database_service)
    {
    }

    void some_logic() {
        network_service_.some_logic();
        database_service_.some_logic();
    }

private:
    NetworkService network_service_;
    DatabaseService database_service_;
};
```


ファンクターを渡す
=====

コールバックを渡すイメージですね。

```cpp
class business_logic
{
public:
    void business_logic(std::function<void()> const& network_service, std::function<void()> const& database_service)
    :   network_service_(network_service)
    ,   database_service_(database_service)
    {
    }

    void some_logic() {
        network_service_();
        database_service_();
    }

private:
    std::function< void() > network_service_;
    std::function< void() > database_service_;
};
```



Javaぽくインターフェースぽいクラスを使って渡す
=====

Java的なオーラがします。

```cpp
class network_service_interface
{
public:
    virtual ~network_service_interface() = 0;
    virtual some_logic() = 0;
};

class database_service_interface
{
public:
    virtual ~network_service_interface() = 0;
    virtual some_logic() = 0;
};

class business_logic
{
public:
    void business_logic(std::shared_ptr<network_service_interface> network_service, std::shared_ptr<database_service_interface> database_service)
    :   network_service_(network_service)
    ,   database_service_(database_service)
    {
    }

    void some_logic() {
        network_service_->some_logic();
        database_service_->some_logic();
    }

private:
    std::shared_ptr<network_service_interface> network_service_;
    std::shared_ptr<database_service_interface> database_service_;
};
```


Javaぽく継承を使って解決する
=====

Javaでいうabstractメソッド的な方法です。

```cpp
class business_logic
{
public:
    void business_logic()
    {
    }

    void some_logic() {
        network_logic();
        database_logic();
    }

private:
    virtual void network_logic() = 0;
    virtual void database_logic() = 0;
};
```


CRTPを使って解決する
=====

```cpp
template <typename Impl>
class business_logic
{
public:
    void business_logic()
    {
    }

    void some_logic() {
        static_cast<Impl*>(this)->network_logic();
        static_cast<Impl*>(this)->database_logic();
    }
};
```

使い方あってる？


マクロでなんとかする
=====

可能なら避けたいですが、場合の手段でしょうか。

```cpp
class business_logic
{
public:
    void business_logic()
    {
    }

    void some_logic() {
#if !defined(USE_STUB)
        network_logic();
        database_logic();
#else
        network_logic_stub();
        database_logic_stub();
#endif
    }
};
```


リンカーでなんとかする
=====

これも場合の手段でしょうか。

```bash
gcc -lnetwork_stub -ldatabase_stub business_logic.c
```




環境変数や設定ファイルでなんとかする
=====

実行時に処理を分岐することも考えられます。
スクリプト言語だとふつうの方法ですね。