web-dev-qa-db-ja.com

MockitoでSpringの自動接続された@Valueフィールドをモックするにはどうすればよいですか?

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つのフィールドの値をどのようにモックできますか?

87
Dave

SpringのReflectionTestUtils.setFieldの魔法を使用して、コードに変更を加えないようにすることができます。

this チュートリアルで詳細を確認してください。ただし、このメソッドは非常に使いやすいため、おそらく必要ないでしょう。

UPDATE

Spring 4.2.RC1の導入以来、クラスのインスタンスを提供することなく静的フィールドを設定できるようになりました。 this ドキュメントの一部および this commitを参照してください。

104
geoand

@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")
70
BAERUS

プロパティ設定をテストクラスにモックすることもできます

@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);
   }
}
31
Manuel Quinones

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)テストを実装の詳細に結合しません(リフレクションは文字列を使用してフィールド名に結び付けます、フィールド名を変更すると問題が発生する可能性があります)。

13
Mark

この魔法の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;
   ...
12
Thibault

また、クラスには明示的な「セッター」メソッド(たとえば、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");
0
Dherik

私は以下のコードを使用し、それは私のために働いた:

@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/

0
Mendon Ashwini