SpringBoot單元測試使用@Test沒有run方法的解決方案
SpringBoot單元測試使用@Test沒有run方法
吐了!一個關(guān)鍵字,糾錯兩小時,看了十幾篇博客。。。。最后重新建測試類發(fā)現(xiàn)@Test又有用,結(jié)果發(fā)現(xiàn)是因為默認(rèn)的Tests測試類沒有public關(guān)鍵字!


這個破錯改了兩小時。。。
==后續(xù)來了:==
原因找到了
建項目的時候是默認(rèn)的2.3.0,所以默認(rèn)創(chuàng)建的類結(jié)構(gòu)應(yīng)該是2.3.0版本的。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
emmm。之前因為改成了2.1.7.RELEASE,版本不同,項目的結(jié)構(gòu)也不同。
現(xiàn)在用回2.3.0RELEASE
是可以正常跑的。。。而且也沒有了@RunWith注解

SpringBoot寫單元測試遇到的坑
近期,項目需要寫單元測試。我著手的項目是用SpringBoot寫的。所以就簡單的研究了一下如何使用。在使用中遇到不少問題,不得已換了一種方式寫測試用例,寫完之后總感覺不太爽。今天在Spring官網(wǎng)上學(xué)一個新的用法,發(fā)現(xiàn)這種測試方法使用后沒有問題。所以來寫一點筆記。
SpringBoot怎么寫單元測試
SpringBoot提供注解的方式編寫單元測試,可以使用SpringBootTest注解來標(biāo)示測試類。
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootTest{
@Test
public void method(){
}
}這樣寫只能解決沒有一些配置文件的測試邏輯,比如沒有數(shù)據(jù)庫配置、數(shù)據(jù)庫連接池配置等。如果有這些配置,你就需要這樣寫了。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
@Test
public void method(){
}這樣就可以正常運行了。
測試controller類。使用了Mock,網(wǎng)上大多流傳的是下面這種方法,添加@WebAppConfiguration,使用MockMvc去進(jìn)行單元測試,但是我的項目如下使用就出現(xiàn)了問題,執(zhí)行的時候找不到Controller類,網(wǎng)上百度了各種方法都不管用。都會報 no bean of 'controller' type found錯誤。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
@WebAppConfiguration
public class ControllerTest {
private MockMvc mockMvc;
@Autowired
private WebApplicationContext wac;
@Before // 在測試開始前初始化工作
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
@Test
public void getMessageTest() throws Exception {
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/test/getMessage"))
.andDo(MockMvcResultHandlers.print()).andReturn();
int status = mvcResult.getResponse().getStatus();
String content = mvcResult.getResponse().getContentAsString();
Assert.assertTrue("success", status == 200);
Assert.assertFalse("failed", status != 200);
System.out.println("content" + content);
}后來換了一種方式直接new個controller。測試運行后不報no bean of 'controller' type found錯誤了,但是在controller中使用的service報了空指針異常NPE,傳遞性就很明顯了,controller是new的一個對象,所以注解不起作用,service就為null。
最后通過使用@AutoConfigureMockMvc+@MockBean的方式可以實現(xiàn)簡單的單元測試,并且不會對數(shù)據(jù)產(chǎn)生影響,且不會對數(shù)據(jù)庫產(chǎn)生影響。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
@AutoConfigureMockMvc
public class ImkfMessageReportControllerTest {
/**
* 初始化MockMvc
*/
@Autowired
private MockMvc mvc;
/**
* 測試的controller
*/
@MockBean
private UserController userController;
@Test
public void getUserListTest() throws Exception {
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.get("/user/getUserList"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn();
String content = mvcResult.getResponse().getContentAsString();
System.out.println("content" + content);
}SpringBoot使用Mockito進(jìn)行單元測試
上面是使用MockMvc,雖然能夠驗證短鏈接甚至service代碼邏輯的正確性,能夠正常測試接口的問題。但是缺點也不少,比如,覆蓋率并沒有提升。Mockito是一個非常好用的單元測試工具,它的實現(xiàn)原理是繼承要Mock的類,將所有的公有方法進(jìn)行重寫
@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {
@Mock
private UserMapper userMapper;
@InjectMocks
private UserService userService;
@Test
public void saveTest() throws Exception {
User user = new User();
user.setUserName(Long.valueOf("springBoot"));
when(userMapper.insert(user)).thenReturn(user);
int num = userService.save(user);
Assert.assertEquals("success", 1, 1);
}
}使用RunwWith(MockitoJUnitRunner.class)(也可以使用SpringBootRunner.class)來進(jìn)行mocktio測試,注解@Mock標(biāo)記一個類或者接口是需要被mock的,在Mock的過程中就相當(dāng)于@Resource,但是注意一點是Mock是繼承or實現(xiàn)了Mock的類,所以Mock出來的方法,全是null或者返回值為null。@InjectMocks將所有的mock對象都放入需要測試的類的對象中。在上面的saveTest方法里面調(diào)用到UserMapper.insert(),那么需要對UserMapper.insert()進(jìn)行打樁,設(shè)置預(yù)期返回值。
打樁的時候需要注意:傳遞的參數(shù)(如果有)必須為調(diào)用時的同一個對象或者相同值,如果傳入的參數(shù)是一個對象,那么需要對這個對象進(jìn)行打樁,再打樁這個方法。比如,when(userMapper.insert(user)).thenReturn(rUser),插入一個user對象,如果user插入之前要進(jìn)行校驗或者其他操作,需要對這個對象進(jìn)行打樁(當(dāng)然pojp對象可以直接new)。
如果插入的對象非常復(fù)雜,用構(gòu)造方法來構(gòu)造一個空對象,或者構(gòu)造方法所用的對象不能直接構(gòu)造,但是沒有public的方法來設(shè)置值,該如何解決這個問題?我們知道一個對象的類可能有g(shù)et方法(不一定是get,但是只要我們想獲取這個對象中的參數(shù),那么就有public的方法獲?。?,我們可以通過Mock這個對象,在將要測試的方法體內(nèi),如果某行調(diào)用了這個對象的任意方法(toString()、equals()、get()),我們都可以以相同的參數(shù)(如果遇到參數(shù)未知可以用any(),一般都能知道)進(jìn)行打樁后設(shè)置返回值,這樣就能通過參數(shù)校驗等環(huán)節(jié),執(zhí)行后面的代碼邏輯,同時能夠提高覆蓋率,偽代碼如下。
@Mock
private User user;
when(user.get(eq("userName"))).thenReturn("testAdmin");
when(user.get(eq("seq"))).thenReturn(4);
when(user.get(eq("password"))).thenReturn("123456");
when(user.get(eq("u_id"))).thenReturn("654321");通過真實測試用例測試代碼
Mockito測試需要設(shè)置參數(shù)和預(yù)期返回值,在方法體中遇到的所有未知對象(除了方法體中new的對象不需要)都需要進(jìn)行模擬,但是在SpringBoot代碼剛剛完成的初期時,跟想模擬真實場景下進(jìn)行單元測試代碼問題or配置問題,那么通過自動注入的方式引入對象是一種更好的選擇。
ProviderServiceImpl.java -----服務(wù)類
import com.alibaba.dubbo.config.annotation.Service;
import com.example.demo.service.DemoService;
@Service
public class ProviderServiceImpl implements DemoService {
@Override
public String sayHello(String name) {
return "hello " + name + " !";
}
}
DemoApplicationTests.java -----測試類
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
@Resource
DemoService providerService;
@Test
public void contextLoads() {
String result = providerService.sayHello("Spring Boot Test");
System.out.println("result is "+result);
Assert.assertEquals("success","hello Spring Boot Test !" ,result);
}
}這里需要注意的是DemoApplicationTests 需要跟啟動類main在同一級目錄下,如果跟mvc在同一層可以會出現(xiàn)部分bean掃描不到的情況。如目錄層級很深或者程序啟動比較慢的話,可以去掉SpringBootTest(去掉后就不啟動程序,只會運行該測試),運行一下,測試結(jié)果如下:

通過這種注解的方式,可以測試dubbo連接(Refernce注解),可以測試controller層,redis數(shù)據(jù),mysql數(shù)據(jù),都會真實模擬,你只需要在注入你需要測試的類,在類的入口傳入測試參數(shù),在測試過程中,最好采用debug的方式,這樣你可以看到每一步的數(shù)據(jù),也便于定位程序的問題(當(dāng)然也可以出現(xiàn)問題時使用debug)。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
基于Protobuf動態(tài)解析在Java中的應(yīng)用 包含例子程序
下面小編就為大家?guī)硪黄赑rotobuf動態(tài)解析在Java中的應(yīng)用 包含例子程序。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-07-07
mybatis中實現(xiàn)枚舉自動轉(zhuǎn)換方法詳解
在使用mybatis的時候經(jīng)常會遇到枚舉類型的轉(zhuǎn)換,下面這篇文章主要給大家介紹了關(guān)于mybatis中實現(xiàn)枚舉自動轉(zhuǎn)換的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。2017-08-08
在Java開發(fā)中無法繞開的SpringBoot框架詳解
SpringBoot是一個基于Spring框架的快速開發(fā)框架,它的出現(xiàn)極大地簡化了Spring應(yīng)用的開發(fā)流程,SpringBoot是一個快速開發(fā)的框架,它提供了一種快速構(gòu)建應(yīng)用程序的方式,本文給大家介紹在Java開發(fā)中無法繞開的框架:SpringBoot,感興趣的朋友一起看看吧2023-09-09
Seata AT模式TransactionHook被刪除探究
這篇文章主要為大家介紹了Seata AT模式TransactionHook被刪除探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11

