【maven】【spring boot】【單元測試】 使用controller 執行單元測試類


  存在這樣一個場景: 

    當項目啟動時間過長,又沒辦法縮短的時候,寫單元測試就是一個十分耗時的工作,

    這工作不在於使用編寫代碼,而在於每次run junit test 都需要完整啟動一次項目,白白浪費寶貴的生命。

    當由於某個字段沒有賦值,或者某個簡單判斷寫錯,導致需要再等個3-5分鍾啟動 junit test,是否會想要執行一次san check?  

  於是乎:

    假若能使用controller來調用test類方法的話,那么在本地調試單元測試時,對於一些簡單的代碼修改,

    通過熱部署,只需要重新進行一次url訪問就可執行一個完整的單元測試,

    無需再次啟動整個項目。

  正題:

    1. 如何在controller訪問src/test ?

    2. 如何編寫 ?

 

  如何在controller訪問src/test

    maven項目的默認配置中, src/test目錄是測試目錄,不會被編譯到jar中,也就是在controller調用時會報ClassNotFoundException

    解決辦法最好的是在pom文件中修改maven默認的測試目錄,將src/test 作為正常目錄使用

    <build><!-- 將測試目錄更改為其他目錄 -->
    	<testSourceDirectory>src/main/test</testSourceDirectory> 
    </build>

  需要重新maven-update。update后重新將src/test use for building path

  完成后便可以成功啟動項目,並可以正常訪問。

 

 

  如何編寫

    可以做一個參考:

controller,最主要內容在於使用controller時,junit的自動回滾可能不會生效,所以手動設置事務,手動觸發回滾

@RestController
@RequestMapping(value = "/junit", produces = "application/json;charset=utf-8")
public class TestController {
    
    private final Logger logger = LoggerFactory.getLogger(TestController.class);
    
    @Autowired
    private BizTest bizTest;

    @GetMapping("test")
@Transactional(rollbackFor = Exception.class)
public void startJunit() { bizTest.insertTest(); // 手動開啟事務回滾 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } }

測試類,即可以通過其他類訪問,也可以直接執行junit,增加@Componet 或者@Service 還可以通過spring注入方式調用

@Component
public class BizTest extends AbstractTest {

    @Autowired
    private Biz biz;
    
    @Test
    public void insertTest() {
        // 測試業務
    }
}

測試抽象父類,用於直接使用junit測試時的配置

@RunWith(SpringRunner.class)
@SpringBootTest(classes = WebApplication.class)
@Transactional
// @Rollback(false)
public abstract class AbstractTest {

    protected final Logger logger = LoggerFactory.getLogger(AbstractTest.class);

    protected void println(Object object) {
        System.out.println(object);
    }
}

 

 

改進: Controller 與Test類解耦

  直接在controller引用Test類,提交代碼后容易引起打包錯誤,這里就需要對兩者進行解耦。

  咱的解決辦法如下:

     利用spring動態bean注冊+類限定名來令兩者解耦,並令Test類接受spring容器管理,代碼如下:

@GetMapping("test")
    @ResponseBody
    public String startJunit() {
     // 測試主類限定名 String testImplName
= "com.terra.test.JunitTester";
     // 若bean未注冊,則注冊,SpringConetxtUtil可參考其余地方的Spring動態注冊bean
if (SpringContextUtil.getBean(testImplName) == null) { registerBean(testImplName); } try { IJunitTest junitTester = SpringContextUtil.getBean(testImplName); junitTester.startTest(); } catch (Exception e) { if (e.getClass() != UnexpectedRollbackException.class) { return e.getMessage(); } } logger.info("執行單元測試成功"); return "操作成功, 執行完成時間:" + DateUtil.getNowDateTime(); }   // 注冊bean private void registerBean(String className) { DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) SpringContextUtil.getApplicationContext().getAutowireCapableBeanFactory(); if (beanFactory.getBean(className) == null) { BeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClassName(className); beanFactory.registerBeanDefinition(className, beanDefinition); } }   // 單元測試主類接口 public static interface IJunitTest { void startTest(); }

測試主類代碼:

@Component
public class JunitTester extends AbstractTest implements IJunitTest {

    @Autowired
    private BizTest1 bizTest1;
    @Autowired
    private BizTest2 bizTest2;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void startTest() {
        // 手動開啟事務回滾
        bizTest1.before();
        bizTest1.test();
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
}

 

這樣做的好處是,環境上的代碼沒有src/test也不會報錯,而本地只需要進行注釋和去除注釋@RequestMapping,便無需要再修改controller代碼

所有單元測試代碼操作便可在測試主類及其測試類中進行,可喜可賀。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM