Spring 3.1.4.RELEASEとMockito 1.9.5を使用しています。私のSpringクラスには:
@Value("#{myProps['default.url']}")
private String defaultUrl;
@Value("#{myProps['default.password']}")
private String defaultrPassword;
// ...
現在次のように設定しているJUnitテストから:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:test-context.xml" })
public class MyTest
{
「defaultUrl」フィールドの値をモックしたいと思います。他のフィールドの値をモックしたくないことに注意してください。それらをそのままにしておきたいので、「defaultUrl」フィールドのみを保持します。また、クラスには明示的な「セッター」メソッド(setDefaultUrl
など)がなく、テストだけのためにメソッドを作成したくないことに注意してください。
これを考えると、その1つのフィールドの値をどのようにモックできますか?
@Valueフィールドをモックする方法を常に忘れてしまったので、このSO投稿にグーグルで取り組むのは3回目です。受け入れられた答えは正しいものの、「setField」呼び出しを正しく行うには常に時間が必要なので、少なくとも自分用にここにサンプルスニペットを貼り付けます。
生産クラス:
@Value("#{myProps[‘some.default.url']}")
private String defaultUrl;
テストクラス:
import org.springframework.test.util.ReflectionTestUtils;
ReflectionTestUtils.setField(instanceUnderTest, "defaultUrl", "http://foo");
// Note: Don't use MyClassUnderTest.class, use the instance you are testing itself
// Note: Don't use the referenced string "#{myProps[‘some.default.url']}",
// but simply the FIELDs name ("defaultUrl")
プロパティ設定をテストクラスにモックすることもできます
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:test-context.xml" })
public class MyTest
{
@Configuration
public static class MockConfig{
@Bean
public Properties myProps(){
Properties properties = new Properties();
properties.setProperty("default.url", "myUrl");
properties.setProperty("property.value2", "value2");
return properties;
}
}
@Value("#{myProps['default.url']}")
private String defaultUrl;
@Test
public void testValue(){
Assert.assertEquals("myUrl", defaultUrl);
}
}
ReflectionTestUtils
クラスを使用する代わりに、@Value
- annotatedフィールドをパラメーターとしてコンストラクターに渡す関連ソリューションを提案したいと思います。
これの代わりに:
public class Foo {
@Value("${foo}")
private String foo;
}
そして
public class FooTest {
@InjectMocks
private Foo foo;
@Before
public void setUp() {
ReflectionTestUtils.setField(Foo.class, "foo", "foo");
}
@Test
public void testFoo() {
// stuff
}
}
これを行う:
public class Foo {
private String foo;
public Foo(@Value("${foo}") String foo) {
this.foo = foo;
}
}
そして
public class FooTest {
private Foo foo;
@Before
public void setUp() {
foo = new Foo("foo");
}
@Test
public void testFoo() {
// stuff
}
}
このアプローチの利点:1)依存関係コンテナーなしでFooクラスをインスタンス化できます(単なるコンストラクターです)、2)テストを実装の詳細に結合しません(リフレクションは文字列を使用してフィールド名に結び付けます、フィールド名を変更すると問題が発生する可能性があります)。
この魔法のSpring Testアノテーションを使用できます:
@TestPropertySource(properties = { "my.spring.property=20" })
org.springframework.test.context.TestPropertySource を参照してください
たとえば、これはテストクラスです。
@ContextConfiguration(classes = { MyTestClass.Config.class })
@TestPropertySource(properties = { "my.spring.property=20" })
public class MyTestClass {
public static class Config {
@Bean
MyClass getMyClass() {
return new MyClass ();
}
}
@Resource
private MyClass myClass ;
@Test
public void myTest() {
...
そして、これはプロパティを持つクラスです:
@Component
public class MyClass {
@Value("${my.spring.property}")
private int mySpringProperty;
...
また、クラスには明示的な「セッター」メソッド(たとえば、setDefaultUrl)がなく、テストだけのために作成したくないことにも注意してください。
これを解決する1つの方法は、テストとSpringインジェクションに使用されるConstructor Injectionを使用するようにクラスを変更することです。これ以上の反射:)
したがって、コンストラクタを使用して任意の文字列を渡すことができます。
class MySpringClass {
private final String defaultUrl;
private final String defaultrPassword;
public MySpringClass (
@Value("#{myProps['default.url']}") String defaultUrl,
@Value("#{myProps['default.password']}") String defaultrPassword) {
this.defaultUrl = defaultUrl;
this.defaultrPassword= defaultrPassword;
}
}
そして、あなたのテストでは、それを使うだけです:
MySpringClass MySpringClass = new MySpringClass("anyUrl", "anyPassword");
私は以下のコードを使用し、それは私のために働いた:
@InjectMocks
private AccessFeatureActivationStrategy activationStrategy = new AccessFeatureActivationStrategy();
@Before
public void setUp() {
ReflectionTestUtils.setField(activationStrategy, "constantFromConfigFile", 3);
}
参照: https://www.jeejava.com/mock-an-autowired-value-field-in-spring-with-junit-mockito/