2016-06-22 77 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; 
     } 
    } 
} 
相關問題