web-dev-qa-db-ja.com

@InjectMocksを使用して文字列プロパティを挿入する

私はこのコンストラクタを持つSpring MVC @Controllerを持っています:

@Autowired
public AbcController(XyzService xyzService, @Value("${my.property}") String myProperty) {/*...*/}

このコントローラーのスタンドアロンユニットテストを作成します。

@RunWith(MockitoJUnitRunner.class)
public class AbcControllerTest {

    @Mock
    private XyzService mockXyzService;

    private String myProperty = "my property value";

    @InjectMocks
    private AbcController controllerUnderTest;

    /* tests */
}

Stringプロパティを挿入する@InjectMocksを取得する方法はありますか?文字列は不変であるため、モックできないことはわかっていますが、通常の文字列をここに挿入することはできますか?

この場合、@InjectMocksはデフォルトでnullを挿入します。 @Mockは、myPropertyに設定すると例外的にスローされます。 「モックではなく、この正確なオブジェクトを挿入する」という意味の、私が見逃した別の注釈はありますか?

22
Sam Jones

Mockitoでこれを行うことはできません。自分で言ったように、Stringfinalであり、モックできないからです。

realオブジェクトで機能する@Spyアノテーションがありますが、@Mockと同じ制限があるため、スパイできませんStringで。

モックやスパイを行わずにその値を注入するようにMockitoに指示する注釈はありません。しかし、それは良い機能でしょう。おそらく Mockito Githubリポジトリ で提案してください。

コードを変更したくない場合は、コントローラーを手動でインスタンス化する必要があります。

純粋な注釈ベースのテストを行う唯一の方法は、コントローラーをリファクタリングすることです。 1つのプロパティのみを含むカスタムオブジェクト、または複数のプロパティを持つ構成クラスを使用できます。

@Component
public class MyProperty {

    @Value("${my.property}")
    private String myProperty;

    ...
}

これをコントローラーに注入できます。

@Autowired
public AbcController(XyzService xyzService, MyProperty myProperty) { 
    ... 
}

これをモックしてインジェクトでき​​ます。

@RunWith(MockitoJUnitRunner.class)
public class AbcControllerTest {

    @Mock
    private XyzService mockXyzService;

    @Mock
    private MyProperty myProperty;

    @InjectMocks
    private AbcController controllerUnderTest;

    @Before
    public void setUp(){
        when(myProperty.get()).thenReturn("my property value");
    }

    /* tests */
}

これは簡単なことではありませんが、少なくともスタブを少し追加するだけで、純粋な注釈ベースのテストを実行できます。

8
Tom Verelst

Mockitoでこれを行うことはできませんが、Apache Commonsには実際には、組み込みユーティリティの1つを使用してこれを行う方法があります。次のように、Mockitoが残りのモックを注入した後、テストケースが実行される前に実行されるJUnitの関数にこれを配置できます。

@InjectMocks
MyClass myClass;

@Before
public void before() throws Exception {
    FieldUtils.writeField(myClass, "fieldName", fieldValue, true);
}
24
Jacob Beasley

その場合は、@ InjectMocksを使用しないでください。

行う:

@Before
public void setup() {
 controllerUnderTest = new AbcController(mockXyzService, "my property value");
}
2
Jan Groot

Springを使用しているので、org.springframework.test.util.ReflectionTestUtils から spring-testモジュール。オブジェクトのフィールドまたはクラスの静的フィールドの設定を(他のユーティリティメソッドと共に)きちんとラップします。

@RunWith(MockitoJUnitRunner.class)
public class AbcControllerTest {

    @Mock
    private XyzService mockXyzService;

    @InjectMocks
    private AbcController controllerUnderTest;

    @Before
    public void setUp(){
        ReflectionTestUtils.setField(controllerUnderTest, "myProperty", 
               "String you want to inject");
    }

    /* tests */
}
2
jebeaudet

使用できるのはこれです:org.mockito.internal.util.reflection.Whitebox

  1. 「AbcController」クラスコンストラクターをリファクタリングする
  2. Testクラスの「before」メソッドで、Whitebox.setInternalStateメソッドを使用して、必要な文字列を指定します

    @Before
    public void setUp(){
        Whitebox.setInternalState(controllerUnderTest, "myProperty", "The string that you want"); }
    
0
Abhinav Ganguly