2

Mockito でクラスをモックしたい。次に、実際のクラス インスタンスを返すことが期待される .newInstance() 呼び出しが発行されます (私の場合はモックが返されます)。

正しくセットアップされていれば、次のことができます。

ArrayList myListMock = mock(ArrayList.class);
when(myVar.newInstance()).thenReturn(myListMock);

クラス ArrayList の新しいインスタンスが (PowerMockito whenNew を使用して) モックになるように設定できることはわかっていますが、インスタンスの作成をオーバーライドする必要がないように、この種のクラス オブジェクトをモックする方法があったかどうか疑問に思っています。 ...

以下は、モックしようとしている実際のクラスです。インターフェイスによって定義されている構造を変更することはできません。私が探しているのは、initialize が呼び出されたときに cvs を提供する方法です。

public class InputConstraintValidator 
    implements ConstraintValidator<InputValidation, StringWrapper> {

    Class<? extends SafeString> cvs;

    public void initialize(InputValidation constraintAnnotation) {
        cvs = constraintAnnotation.inputValidator();
    }

    public boolean isValid(StringWrapper value, 
                   ConstraintValidatorContext context) {

        SafeString instance;
        try {
             instance = cvs.newInstance();
        } catch (InstantiationException e) {
            return false;
        } catch (IllegalAccessException e) {
            return false;
    }
}
4

2 に答える 2

0

Mockito は、オブジェクトのインスタンスをモックするためだけに設計されています。内部的には、モック メソッドは実際にはすべての非最終メソッドへの呼び出しを受け取るプロキシを作成し、必要に応じてそれらの呼び出しをログに記録してスタブ化します。Mockito を使用して Class オブジェクト自体の関数を置き換える良い方法はありません。これにより、いくつかのオプションが残ります。

  1. PowerMock の経験はありませんが、静的メソッドをモックするために設計されているようです

  2. 依存性注入スタイルでは、静的ファクトリ メソッドをファクトリ インスタンスにします。あなたは実際には を扱っていないように見えるので、代わりにArrayListあなたのクラスが次のようになっているとしましょう:FooBar

    class FooBar {
      static class Factory {
        static FooBar instance;
        FooBar getInstance() {
          if (instance == null) {
            instance = new FooBar();
          }
          return instance;
        }
      }
      // ...
    }
    

    これで、クラスのユーザーはnew FooBar.Factory()パラメーターを受け取ることができます。これにより、実際の FooBar がシングルトン スタイルで作成されます (私の単純な実装よりも優れていて、よりスレッドセーフであることを願っています)。また、純粋な Mockito を使用して Factory をモックできます。これがボイラープレートのように見える場合は、それが原因ですが、Guiceのような DI ソリューションに切り替えることを考えている場合は、その多くを削減できます。

  3. フィールドまたはメソッドをパッケージ プライベートまたは保護し、テスト目的で表示可能であることを文書化することを検討してください。次に、モック化されたインスタンスをテスト コードにのみ挿入できます。

    public class InputConstraintValidator implements 
        ConstraintValidator<InputValidation, StringWrapper> {
      Class<? extends SafeString> cvs;
    
      public void initialize(InputValidation constraintAnnotation) {
        cvs = constraintAnnotation.inputValidator();
      }
    
      public boolean isValid(StringWrapper value,
          ConstraintValidatorContext context) {
        SafeString instance;
        try {
          instance = getCvsInstance();
        } catch (InstantiationException e) {
          return false;
        } catch (IllegalAccessException e) {
          return false;
        }
      }
    
      @VisibleForTesting protected getCvsInstance()
          throws InstantiationException, IllegalAccessException {
        return cvs.newInstance();
      }
    }
    
    public class InputConstaintValidatorTest {
      @Test public void testWithMockCvs() {
        final SafeString cvs = mock(SafeString.class);
        InputConstraintValidator validator = new InputConstraintValidator() {
          @Override protected getCvsInstance() {
            return cvs;
          }
        }
        // test
      }
    }
    
于 2012-10-25T00:25:21.030 に答える
-1

の追加のモックを導入するだけでよいと思いますClass

ArrayList<?> myListMock = mock(ArrayList.class);
Class<ArrayList> clazz = mock(Class.class);
when(clazz.newInstance()).thenReturn(myListMock);

もちろん、トリックは、モックclazz.newInstance()化されたものがあちこちで呼び出されないようにすることClass<ArrayList>です。

また、基本的なものに対して独自のモックを定義するように注意してください。ArrayList通常、私は「本物のモック」を使用してモックを設定します。

于 2012-10-24T23:50:15.497 に答える