1

次のコードとほぼ同等のコードがあります。


public class ConcreteThread extends OtherThread {
  private DAOfirst firstDAO;
  private DAOsecond secondDAO;
  private TransformService transformService;
  private NetworkService networkService;

  public ConcreteThread(DAOfirst first, DAOsecond second, TransformService service1, 
       NetworkService service2) {
    firstDAO = first;
    secondDAO = second;
    transformService = service1;
    networkService = service2;
  }

  public Future go() {
    Results r1 = firstDAO.getResults();
    MyCallable c1 = new MyCallable(r1);
    return super.getThreadPool().submit(c1);
  }

  private class MyCallable implements Callable {   
    private Results result; 
    private Long count;
    private MyCallable(Results r) {
      this.result = r;
      this.count = new Long(0);
    }

    public Long call() {
      Singleton transactions = Singleton.getInstance();
      try {
        transactions.begin();
        while(result != null) {
          Transformed t = transformService.transform(r1);
          networkService.sendSomewhere(t);
          count = count += result.size();
          secondDao.persist(result);
          result = firstDao.getNext(result);
        }
      }
      catch (Exception e) {
        e.printStackTrace();
      }
      finally {
         transactions.end(); 
      }
    }
  }
 

これらのクラス(内部クラスまたは外部クラス)のどちらにも単体テストがなく、内部クラスにMyCallableバグがあることがわかりました。上で示したコードの簡略化されたバージョンでは、バグは存在しません。

したがって、バグを修正することを決定し、の単体テストを実装するとしますMyCallable。私の質問はこれです。MyCallable内部クラスの単体テストをどの程度正確に記述しますか?

私自身の解決策は、最初にリファクタリングMyCallableしてConcreteThreadMyCallableは独自のファイルでパブリッククラスになり、内部クラスのプライベート変数へのアクセスに依存するのではなくConcreteThread、DAO、Services、およびSingletonをコンストラクター引数として渡すようになりました。MyCallable

次に、単体テストでEasyMockを多用して、これらの依存関係をモックし、期待どおりに呼び出されていることを確認しました。

これらすべての結果として、のコードMyCallableは以前よりもいくらか大きくなります。のプライベート変数にアクセスできなくなったため、コンストラクターの引数としてそれらを渡し、プライベート変数として設定する必要がありConcreteThreadます。ConcreteThreadMyCallable

これは間違ったアプローチだったと思いますか?それはおそらく、この種のリファクタリングを実行することによって、カプセル化を破り、コードベースに不要な定型文を追加したのでしょうか?代わりに、テストでリフレクションを使用しましたか?

4

2 に答える 2

3

このすべての結果として、MyCallableのコードは以前よりもいくらか大きくなります。ConcreteThreadのプライベート変数にアクセスできなくなったため、ConcreteThreadはそれらをコンストラクターの引数として渡す必要があり、MyCallableはそれらをプライベート変数として設定します。

これは良い結果です。MyCallableはConcreteThreadの変更に依存しなくなりました。

質問と回答はかなり主観的なものだと思いますが、リファクタリングではSOLIDの原則に従っていると思います(これは良いことです)。

そして、可能であれば、MyCallableパッケージを公開ではなく保護します:)

于 2011-02-18T11:33:00.457 に答える
1

私には、内部クラスは外部クラスの実装の詳細です。

だから私はこの質問を提起します. ConcreteThread.Go() の失敗した単体テストを書いてバグを実証できますか? 内部クラスに変更を加えると何が変わるはずですか? 外部から見える変更は何でしょうか? あなたがそれを理解したら、あなたはあなたの道を歩むでしょう.

于 2011-02-18T12:07:26.190 に答える