2016-06-22 44 views
4

我在测试类中实例化时导致@Value注释返回null的服务中使用自动装配构造函数。自动装配依赖关系直接解决了问题,但该项目遵循使用基于构造函数的自动装配的约定。我的理解是,在测试类中实例化服务不是从Spring IoC容器创建的,它导致@Value返回null。有没有办法使用基于构造函数的自动装配从IoC容器创建服务,而无需直接访问应用程序上下文?Spring @Autowired构造函数在测试类中实例化时使@Value返回null

示例服务:

@Component 
public class UpdateService { 

    @Value("${update.success.table}") 
    private String successTable; 

    @Value("${update.failed.table}") 
    private String failedTable; 

    private UserService userService 

    @Autowired 
    public UpdateService(UserService userService) { 
     this.userService = userService; 
    } 
} 

实例测试服务:

@RunWith(SpringJUnite4ClassRunner.class) 
@SpringApplicationConfiguration(classes = {TestApplication.class}) 
@WebAppConfiguration 
public class UpdateServiceTest { 

    private UpdateService updateService; 

    @Mock 
    private UserService mockUserService; 

    @Before 
    public void setUp() { 
     MockitoAnnotations.initMocks(this); 

     updateService = new UpdateService(mockUserService); 

    } 
} 
+0

如果你有'UpdateService' bean,只需'@ Autowired'它。 –

+0

不幸的是,这并不能帮助我,因为我需要能够在测试类中使用模拟对象构建UpdateService。 – Alex

+0

对,错过了。看看[这里](http://stackoverflow.com/questions/2457239/injecting-mockito-mocks-into-a-spring-bean)提示。 –

回答

2

为了使@Value工作updateService应该是Spring上下文内。

为Spring框架集成测试的最佳实践是包括在测试中的测试环境和自动装配测试源应用程序上下文:

... 
public class UpdateServiceTest { 
    @Autowired 
    private UpdateService updateService; 
    ... 

模拟userService

不断变化userServiceprotected和考虑选项该测试和源类在相同的包中。

@Before 
public void setUp() { 
    MockitoAnnotations.initMocks(this); 

    updateService.userService = mockUserService; 
} 

期权反射与Whitebox

@Before 
public void setUp() { 
    MockitoAnnotations.initMocks(this); 

    Whitebox.setInternalState(updateService, 'userService', mockUserService); 
} 
+0

不幸的是,直接自动引用UpdateService并不能帮助我,因为我需要能够使用模拟的UserService对象构造对象 – Alex

+0

@Alex没关系,为此您有两个选项,您可以使'private UserService userService'受保护并交换真实通过分配模拟实例或使用反射来更改专用字段来模拟bean。 – gevorg

+0

我想避免直接设置UserService。使用反射与Whitebox做了诀窍,谢谢! – Alex

1

@Value的由属性占位符配置器这是在弹簧上下文后处理器填充。由于您的​​不是上下文的一部分,因此不处理。

您的设置看起来有点像单元和集成测试混合不清。对于单元测试,根本不需要弹簧上下文。简单地使@Value注释成员包保护,设置,或使用ReflectionTestUtils.setField()(中所示):

public class UpdateServiceTest { 

    @InjectMocks 
    private UpdateService updateService; 

    @Mock 
    private UserService mockUserService; 

    @Before 
    public void setUp() { 
     MockitoAnnotations.initMocks(this); 
     ReflectionTestUtils.setField(updateService, "successTable", "my_success"); 
     updateService.failedTable = "my_failures"; 
    } 
} 

对于集成测试的所有接线应该由春季完成。

为此,我添加了一个提供模拟用户服务的内部配置类(@Primary仅用于您在上下文中有任何其他用户服务的情况),并且模拟存储在此处的静态成员中以便对其进行简单访问之后的测试模拟。

@RunWith(SpringJUnite4ClassRunner.class) 
@SpringApplicationConfiguration(classes = {TestApplication.class, UpdateServiceTest.TestAddOn.class}) 
@WebAppConfiguration 
public class UpdateServiceTest { 

    @Autowired 
    private UpdateService updateService; 

    private static UserService mockUserService; 



    static class TestAddOn { 
     @Bean 
     @Primary 
     UserService updateService() { 
     mockUserService = Mockito.mock(UserService.class); 
     return mockUserService; 
     } 
    } 
} 
相关问题