2017-10-13 31 views
0

我們正在與我的同事討論這種方法。他們說只能在集成或功能級別上使用SpringRunner。在單元測試中使用SpringRunner可以嗎?

問題是什麼利弊在下面的級別使用它?

例如,我有簡單的bean:

public class RewardDurationCalculator { 

    private Clock clock; 

    public OptionalLong calculate(DurationType durationType, List<Pass> passes) { 
     long now = Instant.now(clock).getEpochSecond(); 
     switch (durationType) { 
      case FULL_PASS: 
       return getCurrentPassDuration(passes, now); 
      case TILL_THE_END_OF_THE_CURRENT_ACTIVE_PASS: 
       return getTimeInCurrentPassLeft(passes, now); 
     } 
     return OptionalLong.empty(); 
    } 

    private OptionalLong getCurrentPassDuration(List<Pass> passes, long now) { 
     return passes.stream() 
       .filter(currentPass(now)) 
       .mapToLong(Pass::getDuration) 
       .findFirst(); 
    } 

    private OptionalLong getTimeInCurrentPassLeft(List<Pass> passes, long now) { 
     return passes.stream() 
       .filter(currentPass(now)) 
       .mapToLong(pass -> getEndTs(pass) - now) 
       .findFirst(); 
    } 

    private Predicate<Pass> currentPass(long now) { 
     return pass -> pass.getStartTs() >= now && now <= getEndTs(pass); 
    } 

    private long getEndTs(Pass pass) { 
     return pass.getStartTs() + pass.getDuration(); 
    } 

} 

被做一些計算邏輯。對於它,我也Spring配置:

@Configuration 
public class RewardDurationCalculatorConfiguration { 

    @Bean 
    public RewardDurationCalculator rewardDurationCalculator(Clock clock) { 
     return new RewardDurationCalculator(clock); 
    } 

} 

那麼,爲什麼我不能寫單元測試是這樣的:

@RunWith(SpringRunner.class) 
@ContextConfiguration(classes = RewardDurationCalculatorConfiguration.class) 
public class RewardDurationCalculatorTest { 

    @MockBean 
    private Clock clock; 
    @Autowired 
    private RewardDurationCalculator rewardDurationCalculator; 

    @Test 
    public void testCalculateCurrentPassDurationShouldBeReturnedIfPassWasCreatedRightNow() { 
     rewardDurationCalculator.calculate(DurationType.FULL_PASS, Collections.emptyList()); 
    } 

} 

我可以使用這種方法面臨哪些利弊?

回答

4

我傾向於同意你的同事。

單元測試應該只測試小單元的代碼,通常是方法,理想情況下只運行被測單元而不執行任何其他代碼(私有方法除外)。

這樣做的一個原因是單元測試應該儘可能快地執行,所以開發人員可以在每次對代碼進行小改動後儘可能經常地運行它們。你想從單元測試中獲得即時反饋。即使加載Spring上下文通常安靜得快,並且在測試的執行時間上增加了大約一秒,但如果每天執行測試幾百次,那麼這一秒就會讓人厭煩,因爲您應該這樣做,因爲例如,大量重構類。

堅持這一規則的另一個原因是它迫使你編寫高度解耦的類。如果你不能爲只能運行這個類的類編寫單元測試,那麼這可能表明你應該重新考慮你的類設計。

當你爲測試加速整個Spring上下文時,按照這個定義,它不再是一個單元測試,而是一個集成測試,因爲你也在測試整個Spring配置,引導,自動裝配等。即將你的類集成到Spring應用程序中。

1

@SpringRunner應該用在你的類正在使用任何bean依賴關係,如果你的類是獨立的,沒有任何應用上下文依賴關係,最好不要使用@SpringRunner。如果我看到你的類「RewardDurationCalculator」它不使用任何依賴,它不應該使用@SpringRunner,甚至事實的事嘲笑......

對於進一步閱讀:

  1. https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/test/context/junit4/SpringRunner.html
+0

它有一個依賴。它可以被嘲笑的時鐘。但我明白了,謝謝。 – SoulCub

相關問題