在Spring应用程序上下文中注入模拟会创建一个副本

时间:2016-03-30 16:33:27

标签: java spring mockito

我有一个看起来像这样的测试类:

@SpringApplicationConfiguration(classes = RecipesApplicationTest.class) // This test class will configure its own context
@ComponentScan("com.mysmartfridge.domain.recipes") // Scan recipes domain package so that domain services are available
@Import(RecipesApplication.class) // Load the bean that we want to test.
public class RecipesApplicationTest {

    @ClassRule
    public static final SpringClassRule SCR = new SpringClassRule();

    @Rule
    public final SpringMethodRule SMR = new SpringMethodRule();

    @Autowired
    private RecipesRepository recipesRepository;

    private final RecipesRepository recipesRepositoryMock = Mockito.mock(RecipesRepository.class); // final mocks because they are given to spring context.

    // Get the service to test from the context
    @Autowired
    RecipesApplication recipesApplication;

    @Test
    public void addingARecipeShouldMakeItAvailableInRandomRecipes() {
        //given
        RecipeDto dto = new RecipeDto();
        dto.title="test";
        dto.ingredients = new ArrayList<>();
        dto.steps = new ArrayList<>();

        final List<Recipe> recipesInMock = new ArrayList<>();
        Mockito.when(recipesRepository.save(Mockito.any(Recipe.class))).thenAnswer(new Answer<Recipe>() {
            @Override
            public Recipe answer(InvocationOnMock aInvocation) throws Throwable {
                Recipe arg = aInvocation.getArgumentAt(0, Recipe.class);
                recipesInMock.add(arg);
                return arg;
            }
        });

        Mockito.when(recipesRepository.findAll()).thenAnswer(new Answer<List<Recipe>>() {
            @Override
            public List<Recipe> answer(InvocationOnMock aInvocation) throws Throwable {
                return recipesInMock;
            }
        });


        //when
        dto = recipesApplication.createRecipe(dto);
        RecipeDto randomDto = recipesApplication.findRandomRecipe();

        //then
        Assertions.assertThat(randomDto).isEqualTo(dto);
    }

    // Inject the recipeRepository mock in the context
    @Bean
    RecipesRepository recipesRepository() {
        return recipesRepositoryMock;
    }

}

我的问题是recipesRepositoryMock和recipesRepository这两个字段不是同一个对象。因此,如果我在设置我的答案时尝试用recipesRepositoryMock替换recipesRepository(即如果我when(recipesRepositoryMock.save()).thenAnswer(...)),则它不起作用,则永远不会调用自定义答案。

我希望能够摆脱@Autowired recipesRepository,它与recipesRepositoryMock有点重复......

是不是因为我的bean周围添加了一个代理?

2 个答案:

答案 0 :(得分:2)

你可以更好地删除 private final RecipesRepository recipesRepositoryMock = Mockito.mock(RecipesRepository.class);

如果你想模拟一个Spring bean,那么你必须使用@Autowired为Spring创建它。

所以你的测试看起来像:

@SpringApplicationConfiguration(classes = RecipesApplicationTest.class) // This test class will configure its own context
@ComponentScan("com.mysmartfridge.domain.recipes") // Scan recipes domain package so that domain services are available
@Import(RecipesApplication.class) // Load the bean that we want to test.
public class RecipesApplicationTest {

  @ClassRule
  public static final SpringClassRule SCR = new SpringClassRule();

  @Rule
  public final SpringMethodRule SMR = new SpringMethodRule();

  @Autowired
  private RecipesRepository recipesRepository; 

  // Get the service to test from the context
  @Autowired
  RecipesApplication recipesApplication;

  @Test
  public void addingARecipeShouldMakeItAvailableInRandomRecipes() {
   // your test 
  }

  // Inject the recipeRepository mock in the context
  @Bean
  RecipesRepository recipesRepository() {
    return Mockito.mock(RecipesRepository.class);
  }

}

答案 1 :(得分:0)

听起来您正在尝试依赖自动连接,以便Spring正确地将RecipesRepository实例作为依赖项注入RecipesApplicationThis question似乎与你的相似。话虽这么说,我因为你可能没有使用像[ReflectionTestUtils][2]这样的东西而犹豫不决。相反,请尝试删除recipesRepository中的RecipesApplicationTest字段,并保留recipesRepositoryMock字段。但是,在dto = recipesApplication.createRecipe(dto)行之前,请尝试查看是否可以通过recipesRepositoryMock等类似的调用将recipesApplication手动注入recipesApplication.setRecipesRepository(recipesRepositoryMock)