モッキートスーパークラスの方法の呼び出しのみをock笑する方法

StackOverflow https://stackoverflow.com/questions/3467801

  •  28-09-2019
  •  | 
  •  

質問

いくつかのテストでモッキートを使用しています。

私は次のクラスを持っています:

class BaseService {  
    public void save() {...}  
}

public Childservice extends BaseService {  
    public void save(){  
        //some code  
        super.save();
    }  
}   

2回目の呼び出しだけをock笑したい(super.save) の ChildService. 。最初の呼び出しは、実際の方法を呼び出す必要があります。それをする方法はありますか?

役に立ちましたか?

解決

いいえ、モキトはこれをサポートしていません。

これはあなたが探している答えではないかもしれませんが、あなたが見ているのは、設計原則を適用しないという症状です。

継承よりも構成を好む

スーパークラスを拡張する代わりに戦略を抽出すると、問題はなくなります。

ただし、コードを変更することは許可されていないが、とにかくテストする必要があり、この厄介な方法では、まだ希望があります。一部のAOPツール(AspectJなど)を使用すると、コードをスーパークラスメソッドに織り込み、その実行を完全に回避できます(Yuck)。プロキシを使用している場合、これは機能しません。ByteCode変更(ロードタイム織りまたはコンパイル時間織りのいずれか)を使用する必要があります。 PowerMockやPowerMockitoなど、このタイプのトリックもサポートするモッキングフレームワークがあります。

私はあなたがリファクタリングに行くことをお勧めしますが、それがあなたがいくつかの深刻なハッキングの楽しみのためにあなたがいるオプションでなければ。

他のヒント

リファクタリングの選択肢が本当にない場合は、スーパーメソッドのすべてをmock/stabeすることができます。

    class BaseService {

        public void validate(){
            fail(" I must not be called");
        }

        public void save(){
            //Save method of super will still be called.
            validate();
        }
    }

    class ChildService extends BaseService{

        public void load(){}

        public void save(){
            super.save();
            load();
        }
    }

    @Test
    public void testSave() {
        ChildService classToTest = Mockito.spy(new ChildService());

        // Prevent/stub logic in super.save()
        Mockito.doNothing().when((BaseService)classToTest).validate();

        // When
        classToTest.save();

        // Then
        verify(classToTest).load();
    }

ChildService.save()メソッドから異なる方法にコードをリファクトすることを検討し、childService.save()をテストする代わりにその新しい方法をテストすることを検討してください。

例:

class BaseService {  
    public void save() {...}  
}

public Childservice extends BaseService {  
    public void save(){  
        newMethod();    
        super.save();
    }
    public void newMethod(){
       //some codes
    }
} 

スーパークラスメソッドを呼び出すサブクラスで保護されたパッケージ(同じパッケージでテストクラスを想定)メソッドを作成し、オーバーライドされたサブクラスメソッドでそのメソッドを呼び出します。その後、スパイパターンを使用して、テストでこの方法に期待を設定できます。きれいではありませんが、テストのスーパーメソッドのすべての期待設定に対処しなければならないよりも確かに優れています

イウェインの応答に完全に同意しても(

継承よりも構成を好む

)、私は時々相続財産が自然に見えることがあり、私はそれを壊したりリファクタリングしたりすることはないと感じています。

だから、私の提案:

/**
 * BaseService is now an asbtract class encapsulating 
 * some common logic callable by child implementations
 */
abstract class BaseService {  
    protected void commonSave() {
        // Put your common work here
    }

    abstract void save();
}

public ChildService extends BaseService {  
    public void save() {
        // Put your child specific work here
        // ...

        this.commonSave();
    }  
}

そして、ユニットテストで:

    ChildService childSrv = Mockito.mock(ChildService.class, Mockito.CALLS_REAL_METHODS);

    Mockito.doAnswer(new Answer<Void>() {
        @Override
        public Boolean answer(InvocationOnMock invocation)
                throws Throwable {
            // Put your mocked behavior of BaseService.commonSave() here
            return null;
        }
    }).when(childSrv).commonSave();

    childSrv.save();

    Mockito.verify(childSrv, Mockito.times(1)).commonSave();

    // Put any other assertions to check child specific work is done

その理由は、基本クラスが公開されていないため、モッキートは視認性のためにそれを傍受することができません。ベースクラスをパブリックとして、またはサブクラスの@Override(パブリック)で変更すると、モキトはそれを正しくock笑できます。

public class BaseService{
  public boolean foo(){
    return true;
  }
}

public ChildService extends BaseService{
}

@Test
@Mock ChildService childService;
public void testSave() {
  Mockito.when(childService.foo()).thenReturn(false);

  // When
  assertFalse(childService.foo());
}

継承が理にかなっている場合の最も簡単なオプションは、スーパーを呼び出すための新しい方法(パッケージプライベート??)を作成し、実際のインスタンスをスパイしてから、superfindall()メソッドをmockしたい方法でmock superfindall()メソッドをmockすることです。親クラス1。カバレッジと可視性の点では完璧な解決策ではありませんが、仕事をするはずであり、適用するのは簡単です。

 public Childservice extends BaseService {
    public void save(){
        //some code
        superSave();
    }

    void superSave(){
        super.save();
    }
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top