首页 > 其他分享 >springboot JunitTest

springboot JunitTest

时间:2024-05-10 13:44:06浏览次数:22  
标签:springboot Mockito private class JunitTest 测试 test public

junit测试参考官方文档:

https://docs.spring.io/spring-boot/docs/2.0.4.RELEASE/reference/html/boot-features-testing.html

1. 对springboot框架的项目进行测试,需要引入测试包

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

然后在Test类上,创建springboot的引入

@SpringBootTest
@RunWith(SpringRunner.class)

在新版本中用junit4:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes=MySpringApplication.class)

如果是web项目,对controller进行测试,则要引入webServletContext,不然无法获取request和response

@WebAppConfiguration

因Test类是独立运行,要对多个类进行测试,可能会建立多个类的测试类,这时就可以将统一类注解放在一个共通类。让使用类继承即可。(注意不能用接口)

常用测试配置:

  • @Ignore  (忽略某项测试)

  • @FixMethodOrder(MethodSorters.NAME_ASCENDING)   注意:要定义在当前类上,不能定义到启动父类上,在junit5版本用TestMethodOrder代替

  • @TestConfiguration (仅用于测试的configuration)

  • @MockBean(用于容器启动,将某个类作为随机结果返回)

  • Mockito
  • @Mock & @InjectMocks (对于非容器启动类的测试)
  • @Spy
  • @ActiveProfiles (用于定义要使用的application文件)
  • @WebMvcTest(****Controller.class)   (用于单纯测试Controller类)

  • @MybatisTest  (mapper接口测试)

  • Suit(集合测试,用于将多个test用例合为一体测试)

  • @Rule
  • TestCase 和 TestSuit (注解的原身)

  • @Parameterized.Parameters

     

@TestConfiguration

当我们需要引入配置来测试某个类时,就可以创建一个测试用的TestConfiguration,当然为了不和真正的使用有关联,我一般建立在test下,这样就不会有瓜葛。

为了测试MyHttpRequestMvcInterceptor,创建一个测试配置类:

@TestConfiguration
public class MvcInterceptorAssistance extends WebMvcConfigurationSupport {

    /**
     * 在WebMvc配置中设立RequestCounter
     * @param registry
     */
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyHttpRequestMvcInterceptor());
        super.addInterceptors(registry);
    }
}

假设这是我的TestController:

@RestController
public class TestController {

    @GetMapping("/test")
    public String test(){
        return "testResultOk";
    }
}

配置结构:

@RunWith(SpringJUnit4ClassRunner.class)
@Import(MvcInterceptorAssistance.class)
@AutoConfigureMockMvc
@SpringBootTest(classes = SpringMainTest.class,webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,properties = {"grpc.port=11809"}) public class SpringBootBaseTest {

测试Test1-testRestTemplate:

    @Autowired
    private TestRestTemplate testRestTemplate;

    @LocalServerPort
    private int port;

    @Test
    public void test2() throws Exception {
         testRestTemplate.getForEntity("http://localhost:"+port + "/test",String.class);
    }

测试Test2 - MockMvc:

  @Autowired
    private MockMvc mvc;


    @Test
    public void test() throws Exception {
        
mvc.perform(MockMvcRequestBuilders.get("/test").accept(MediaType.APPLICATION_JSON))
                .andExpect(MockMvcResultMatchers.status().isOk());

    ※ 对于Post的json格式,需要注意填写accept,还需要填写contentType,否则会出现类型不匹配。

 

 

@MockBean:

mockbean用于在@springboottest中将指定的类,不作为IOC托管中的bean来使用。即比如我们要测试@Controller的类,controller调用了多个service,其中一个service可能牵扯调用外部或者DB,那么我们就可以在测试中

将此类指定为@MockBean.

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyControllerTest{
@MockBean
private TestService testService;

@Autowired
private MyController myController;

@Test
public void getUser(){
   Mockito.when(testService.remoteGet(Mockito.any(User.class))).thenReturn(user);
   User user = myController.getUser(1234);
}


    ※ @MockBean 用于IOC bean模式,这样@MockBean标记的对象,会抢占原来的bean在IOC中的位置。

 

@Mock & @InjectMocks

当我们有一个spring项目,但是我们又不想通过容器启动(@SpringBootTest),这时候就可以使用单独对bean测试的方式。

测试类使用@InjectMocks , 因测试的类内部会有@Autowired关联的类,关联类要使用@Mock。

@Mock的对象默认是不具备任何方法能力的。也就是类似于空对象,需要在test使用时来指定。

 

@RunWith(SpringRunner.class)
@ActiveProfiles("test")
public class AccountServiceTest {

    @InjectMocks
    private AccountServiceImpl accountService;

    @Mock
    private AccountDao accountDao;


    /**
     * service使用Mock模式调用
     */
    @Test
    public void testService(){
        AccountDto accountDto = new AccountDto();
        accountDto.setId("1234");
        accountDto.setName("test1234");
        Mockito.when(userDao.insert(Mockito.any(Account.class))).thenReturn(1);
        accountService.insert(accountDto);
    }

※ @InjectMocks 要使用具体实现类,不能使用接口定义。可用于spring不启动时的测试。

@Spy

spy的作用就是可以将我们new的对象传入到@MockInject的属性变量中。使用在代替@Bean创建的对象

例如:UserService内部会使用@Autowired RestTemplate restTemplate;这个时候就可以使用@Spy RestTemplate restTemplate = new RestTemplate();来代替。

 

Mockito:

      VOID方法:

Mockito.doNothing().when(userService).addUser(Mockito.any(UserDto.class));

    有返回值测试:

Mockito.when(userDao.insert(Mockito.any(Account.class))).thenReturn(1);
Mock的内容还可判断当前Inject传入的内容是否满足预期
Mockito.doNothing().when(myRedis).hset(Mockito.eq("USER"), Mockito.eq("admin123"), Mockito.eq(JSONObject.toJSONString(userInfo))).thenReturn(true);

 因没有otherwise和反向匹配,当对预期值判断时可使用(双组合):

        Mockito.when(myRedis.hdel(Mockito.anyString(), Mockito.anyString())).thenThrow(ValueMatcherException.class);
        Mockito.when(myRedis.hdel(Mockito.eq("USER"), Mockito.eq("admin123"))).thenReturn(1L);

或者实现Answer接口,自己处理应该的返回值。

class  MyAnswer implements Answer<java.lang.Long> {

    private UserDto userDto;

    public MyAnswer(UserDto userDto){
        this.userDto = userDto;
    }

    @Override
    public java.lang.Long answer(InvocationOnMock invocation) throws Throwable {
        if (StringUtils.equals(invocation.getArgument(0), "User")
            && StringUtils.equals(invocation.getArgument(1), userDto.getUserCode())){
            return 1L;
        }
        throw new IllegalArgumentException();
    }
}

 Mockito.verify 仅测试某个mockbean是否有被执行,执行的次数,并不能判断内部的值。 

@ActiveProfiles (用于定义要使用的application文件)

 当我们属性文件定义 application-test.properties 内部定义了测试要使用的配置信息,那么我们就可以使用@ActiveProfiles("test")类似于 spring.active.profiles=test.

 

@WebMvcTest(****Controller.class)   

用于单纯测试Controller类,通过@MockMvc 测试,其它的用@MockBean标记。

※注意:其实WebMvcTest还是会去查找应用中标注@SpringBootApplication的类,也就是如果应用的启动类中标记了ScanMapper,依然会加载mapperbean的相关对象,尽管当前的测试类跟

这个没有半毛钱关系。因此,需要在测试路径中需要新创建一个@SpringBootApplication的类,在这个类中取消mapperScan,这样就可以了。

@RunWith(SpringRunner.class)
//使用@WebMvcTest只实例化Web层,而不是整个上下文。在具有多个Controller的应用程序中,
@WebMvcTest(TestController.class)
public class TestControllerTest {
    @Autowired
    private MockMvc mockMvc;
    @MockBean
    private MyService myService;
    @Test
    public void testUser() throws Exception {
    
        Mockito.when(myService.getUser("123")).thenReturn(null);
        this.mockMvc.perform(post("/user"))
                    .contentType("application/json"))
                    .andDo(print())
                    .andExpect(status().isOk())
                    .andExpect(null));
    }
}

 但是如果遇到统一配置 WebMvcConfigurer 拦截器内部依赖的bean,则会出现bean实例错误。需要让ctroller绕开。

@RunWith(SpringRunner.class)
@WebMvcTest(MyController.class)
public class MyControllerTest {

    @Autowired
    private MyController myController;

    private MockMvc mockMvc;

    /** 通过覆盖 **/
    @Before
    public void setup() {
        mockMvc = MockMvcBuilders.standaloneSetup(myController).build();
    }

    /**
     *  拦截器内部的bean
     */
    @MockBean
    private MyTestBean myTestBean;

    // ...
}

 


@MybatisTest:

当我们想要测试Mapper层。就可以引入mybatis的test。

 <dependency> 
     <groupId>org.mybatis.spring.boot</groupId> 
     <artifactId>mybatis-spring-boot-starter-test</artifactId> 
     <version>1.3.2</version> 
     <scope>test</scope> 
 </dependency>
@RunWith(SpringRunner.class)
@MybatisTest
//添加以下设置,使用真实数据库
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
// 默认会回滚,可以通过以下设置调整不回滚
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

 

Suit集合测试:

@RunWith(Suite.class)
@Suite.SuiteClasses({AAATest.class,BBBTest.class})
public class suitTest{}

因集合测试不同于单个测试会根据加载的class顺序执行测试用例,且不会中途退出应用启动,因此要注意测试用例之间不能对某个公有变量值有操作。

 不同的测试内容分属不同的集合,较好。

TestCase 和 TestSuit (注解的原身)

我们使用中的@Test,其实也可以是继承TestCase类,方法public,void 以test开头。

public class Test1 extends TestCase {

    public void testApplication() {
        ****
    }
}

@Suit用的是继承TestSuit类。内部方法名为suit,static,public返回Test。

public class SuitTest2 extends TestSuite {

    public static Test suit(){
        TestSuite suite = new TestSuite();
       // suite.addTestSuite(TestSuit3.class); //可添加子suit
        Test testApplication = TestSuite.createTest(Test2.class, "test1"); //添加Test
        suite.addTest(testApplication);
        return suite;
    }
}


/**
 * 测试Main类的方法
*/
 public static void main(String[] args) {
        TestResult result = new TestResult();
        SuitTest2.suit().run(result);
        result.errorCount();
    }
  • @Rule

     用于设定某项规则,然后处理test。这里rule规则只是给我们预留了对应的处理接口,具体的实现逻辑需要自行代码处理。

       

            MethodRule:

                      方法执行Rule。

                      比如,某个Test要多次运行,参数又不一致,如果写到一个Test中,看着很凌乱,且代码量大大增加。这里我们可以自己写个类实现MethodRule接口,处理对应的逻辑代码。

                   这里写了个 ParamsMethodRule

/**
 * Description:参数定义Rule
 *
 * @author Denny.Zhao
 * @since 2021/11/22
 */
public class ParamsMethodRule implements MethodRule {
    private final String testName;
    private final String[] strArray;
    public String params;

    public ParamsMethodRule(String[] strArray, String testName) {
        this.strArray = strArray;
        this.testName = testName;
    }

    public String getParams() {
        return params;
    }

    @Override
    public Statement apply(Statement base, FrameworkMethod method, Object target) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                if (method.getName().equals(testName)){
                    int i=0;
                    do{
                        params = strArray[i];
                        base.evaluate();
                    }while (++i < strArray.length);
                }else{
                       base.evaluate();
                }

            }
        };
    }
}
View Code

 

 

使用的地方引入Rule规则:

@Rule
    public ParamsMethodRule rule = new ParamsMethodRule(new String[]{
            "httpclient.springclient.stats.pending",
            "httpclient.springclient.stats.available",
            "httpclient.springclient.stats.leased",
            "httpclient.springclient.stats.total",
            "httpclient.springclient.stats.max"
        }, "httpClientSpringClientTest");

 

              在@Test方法中通过以下的方式可以获取参数;     

String param = rule.getParams();

   

对于重复性试验,可使用springTest中的@Repeat,需要添加以下Rule。

@Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
  • @Parameterized.Parameters

          用于参数化入参项,重复跑数据用。

1. 定义参数内容

    @Parameterized.Parameters
    public static Collection getName(){
        return Lists.list("DescribeUser",

2. 构造化类

@RunWith(Parameterized.class)
@Slf4j
public class MyTest {

    private String userName;


    public SkiffAuthMgrControllerTest(String userName){
        this.userName= userName;
    }

这样即可重复跑一个case数据了。

 

 

 

 

 

 

 

 

※注意:

JMX关闭:

       由于junit默认是关闭对jmx的访问的,因此如果项目中有@Autowired MBeanServer,会获取为空,如果要打开,则参见:

具体见官方文档:https://docs.spring.io/spring-boot/docs/2.0.4.RELEASE/reference/html/boot-features-testing.html  43.3.6 Using JMX部分

@RunWith(SpringRunner.class)
@SpringBootTest(properties = "spring.jmx.enabled=true")
@DirtiesContext
public class SampleJmxTests {

    @Autowired
    private MBeanServer mBeanServer;

    @Test
    public void exampleTest() {
        // ...
    }

}

 

标签:springboot,Mockito,private,class,JunitTest,测试,test,public
From: https://www.cnblogs.com/DennyZhao/p/9929880.html

相关文章

  • SpringBoot中全部注解归纳解释
    https://blog.csdn.net/weixin_55772633/article/details/131882825https://www.cnblogs.com/jingzh/p/14620211.html1springboot注解1.1引言1.2基本注解1.3JPA注解1.4SpringMVC相关注解1.5全局异常处理1.6项目中具体配置解析和使用环境1.7Lombok注解1.8数......
  • SpringBoot+使用过滤器链执行风控决策
    风控流程下单前进行风控校验//1.begin---风控处理---前置处理{黑白名单校验}RiskControlRuleEnumcontrolRuleEnum=riskControlHandlerService.preHandle(mappingObj.getMerchantGoodsType(),thatUser);if(controlRuleEnum!=null){log......
  • Springboot项目镜像制作&传递环境变量、设置hostname、动态设置JVM参数、cmd&entrypoi
    实现制作一个springboot的镜像,并且可以传递环境变量实现动态JVM参数和端口。0.准备&cmd、entrypoint区别1.准备springboot项目一个简单的springboot项目,默认启动8001端口,里面只有一个接口。xxx%curllocalhost:8081indexdocker环境2.CMD、entrypoint区......
  • springboot3.2.3如何集成swagger
    在SpringBoot中集成Swagger可以方便地生成API文档并进行接口测试。要在SpringBoot3.2.3中集成Swagger,你可以按照以下步骤进行操作:1.添加Swagger依赖到pom.xml文件中:点击查看代码<dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter<......
  • openfeign接口Springboot启动Bean报错未找到Singleton bean creation not allowed whi
    检查步骤检查springboot启动类是否标注@EnableFeignClients注解,未标注该注解会导致无法注入bean检查远程调用模块是否标注注解@FeignClient检查@FeignClient注解中是否写了正确的微服务名称(区分大小写)检查@FeignClient注解中标识的微服务是否启动​​原因:此处接......
  • springboot+vue项目
    1MyBatisPlus的分页插件是怎么生效的?体现在哪里?PaginationInnerInterceptor是通过拦截数据库操作来实现分页功能的。 MyBatisPlus的分页插件PaginationInnerInterceptor是通过拦截数据库操作来实现分页功能的。它的工作原理如下:配置分页插件:在你的SpringBoot应用......
  • SpringBoot随手笔记
    SpringBoot随手笔记0关于火狐浏览器什么时候会发出http请求的说明在抓包的情况下(按下F12后的模式),不管是刷新页面还是在浏览器地址栏回车,该页面中的图片都会发出http请求;但如果不是抓包的模式下,如果访问的页面和上一次访问的页面相同(地址栏的地址没有更改),不管是刷新页面还......
  • springboot seata 全局捕获异常失效
    问题:Springboot使用@ControllerAdvice或@RestControllerAdvice全局捕获异常时,捕获不到自己抛出的相应异常首先看一下全局异常组件有么有被扫描到如何查看,很简单只需要写一段类加载打印代码,如下 如果启动时,打印了你写的字符串就说明时烧苗到了 这就说明是其他的问题了,那就......
  • Springboot项目的jar包的运行方式以及使用yum安装java后忘记了位置
    SpringBoot项目打包后的jar的部署方式这里我写了五种部署方式1.直接启动java-jarxxx.jar这种方式就只适合自己在测试时用一下,关闭会话就能停止运行属实是方便。2.后台启动java-jarxxx.jar&在后台静默启动,同样关闭会话也会停止,优点是和上面一样,日志是打印在窗口的3......
  • Springboot - [06] yaml语法讲解
    Yaml是一种标记语言,Yaml也不是一种标记语言。 一、yaml写法示例application.yaml#普通的key-valuename:harleyserver.port:8081#对象student:name:harleyage:25#对象的行内写法student:{name:harley,age:25}#数组pets:-cat-......