记一次SpringBootTest报错AbstractMethodError

记一次SpringBootTest报错AbstractMethodError文章目录注解@SpringBootTest遇到的问题Pleasesetthe’defaultServletName’propertyexplicitly.JavaAbstractMethodError原因分析最终解决办法做开发,大多数的时间是在人云亦云,尤其是在遇到了问题之后——在百度、CSDN上没有方向地搜索。一旦遇到这样的情况,从基础的文档看起,往往屡试不爽。注解@SpringBootTest@SpringBootTest下的属性:property说明cla

大家好,又见面了,我是你们的朋友全栈君。

做开发,大多数的时间是在人云亦云,尤其是在遇到了问题之后——在百度、CSDN上没有方向地搜索。一旦遇到这样的情况,从基础的文档看起,往往屡试不爽。

注解@SpringBootTest

@SpringBootTest下的属性:

property 说明
classes 启动类
webEnvironment 单元测试web环境,取值参考属性详解

Springboot中我们通常这样在Test类上方添加注解:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = VisitCenterApp.class, webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@Slf4j

遇到的问题

Please set the ‘defaultServletName’ property explicitly.

单元测试时load ApplicationContext失败。

java.lang.IllegalStateException: Failed to load ApplicationContext

	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)
	at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:123)
	at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190)
	at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132)
	at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:244)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:227)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'defaultServletHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: Factory method 'defaultServletHandlerMapping' threw exception; nested exception is java.lang.IllegalStateException: Unable to locate the default servlet for serving static content. Please set the 'defaultServletName' property explicitly.

关键词:Please set the ‘defaultServletName’ property explicitly.
解决办法:
在SwaggerConfig中添加:

@Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { 
   
        configurer.enable("visit-center");
    }

添加之后,果然报错信息变了:

Caused by: org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.AbstractMethodError: org.springframework.boot.test.mock.web.SpringBootMockServletContext.getContextPath()Ljava/lang/String;
	at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:185)
	at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:53)
	at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:360)
	at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:158)
	at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:122)
	at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:894)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:553)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)

相关文档:https://blog.csdn.net/weixin_43114485/article/details/106780813
SpringBoot测试junit遇到的坑

相关称能解决的文档:https://blog.csdn.net/MuErHuoXu/article/details/86750497,但是仍然失败。

最新尝试:看到一个新的注解:@AutoConfigureMockMvc。顺便学习了AutoConfigureMockMvc相关的概念——虽然没能解决我的相关问题。

Spring Boot 2 实战:mock测试你的web应用
spring boot 单元测试使用new MockMvc和@RunWith+@AutoConfigureMockMvc注解的区别

Java AbstractMethodError 原因分析

继续探索:相关内容来自于CSDN。Java AbstractMethodError 原因分析
本文的问题都是来自于一个项目。新猜想:这个项目用到了用到OpenFeign声明一个方法。但是远程调用的方法的声明发生了变化。于是对单元测试造成了影响。

背景

AbstractMethodError异常对于我来说还是比较不常遇见的,最近有幸遇到,并侥幸的解决了,在这里把此种场景剖析一番,进入正题,下面是AbstractMethodError在Java的异常机制中所处的位置:

AbstractMethodError类图

现在明确了AbstractMethodError所具有的特性:

1.它是Error的子类,Error类及其子类都是被划分在非检查异常之列的,就是说这些异常不能在编译阶段被检查出来,只能在运行时才会触发。

2.通过API文档里面的解释大致得出的结论就是说A依赖于B,但是执行的时候发现类B的定义发生了改变,这个改变是针对编译的时候发生了改变,也就是说将类A由java文件编译成.class文件的时候用到了类B的class文件,但是在执行的时候JVM发现真正用到的B的class文件和编译的时候用的不是一个了。于是这个异常就被抛了出来。

至此,AbstractMethodError发生的底层原因也了解的差不多了,再往深层的话就是java的编译机制,以及java代码的执行检查这些更靠近虚拟机的东东,那些我也没什么研究,暂且不表。

底层原因了解了,我们继续谈下平常遇到的更直观的场景:

ClassA ->AbstractClassB ClassA 依赖于AbstractClassB,通常A是我们自己开发的类,而B则是引用的第三方jar包里面的抽象类。我们的项目中又存在AbstractClassB的多个实现版本,比如:1.0,1.2,2.0等版本,通常主版本号发生了改变的话,一般都是不兼容的。

类A

class A { 
   
	B dependency = new BImpl();
	public void testMethod(){ 
   
		dependency.changedMethodInDifVersion(arg1, arg2);
	}
}

1.0版本的AbstractClassB:

abstract class B { 
   
    // v1.0
    public abstract void changedMethodInDifVersion(int arg1);
}
class BImpl extends B{ 
   
    public void changedMethodInDifVersion(int arg1){ 
   
        System.out.prinln("我是AbstractClassB 的 1.0 版本实现,Class A编译的时候我没参与,但是Class A运行的时候我却参与了。");        
    }
}

2.0版本的AbstractClassB:

abstract class B { 
   
    //v2.0
    public abstract void changedMethodInDifVersion(int arg1, String arg2);
}
class BImpl extends B{ 
   
    public void changedMethodInDifVersion(int arg1, String arg2){ 
   
        System.out.prinln("我是AbstractClassB 的 2.0 版本实现,编译的时候是我参与了编译");        
    }
}

如果在编译的时候使用的2.0版本中的BImpl和2.0版本的AbstractClassB,然而执行的时候使用的又是1.0版本的BImpl,那么就会抛出AbstractMethodError,这个异常抛出以后会把运行时真正找到的那个方法签名给打印出来的,异常信息会入下:

Exception in Thread XXXXX java.lang.AbstractMehodError package.Class.运行时实际找到的方法

这个时候在你的classpath中寻找这个类,剔除掉不需要的版本就可以了。

如果在编译的时候使用的2.0版本中的BImpl和2.0版本的AbstractClassB,然而执行的时候使用的又是1.0版本的BImpl 和 1.0版本的AbstractClassB,就会报NoSuchMethodError。

最终解决办法

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-mock</artifactId>
    <version>2.0.8</version>
</dependency>

原来是同事“偷偷”多加了这个jar包,与SpringbootTest产生了jar包冲突,从而导致的单元测试报错。

感谢您的赏读。要不,来个一键三连?点赞、收藏、加关注,
或者留下您的问题让我们一起探讨!一起进步!!

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/141705.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • mdc和mdio是什么_mdc是哪个国家

    mdc和mdio是什么_mdc是哪个国家在项目开发中,经常会巧妙借助MDC解决链路跟踪、统计耗时等很多问题,通过往期分享的《MDC是什么鬼?用法、源码一锅端》,对MDC有了一个深入的了解,但是细心的同学在项目中,偶尔会发现NDC的身影(可能也从未谋面),那NDC到底是个什么玩意呢?别急,通过今天的分享,能让你轻松get如下几点。1.NDC快速入门;2.NDC与MDC有何不同;3.NDC刨根问底1.ND…

    2022年10月24日
  • CPU C-state & cpuidle driver[通俗易懂]

    CPU C-state & cpuidle driver[通俗易懂]1.什么是C-states、C-mode?为了在CPU空闲时节约能源,可以命令CPU进入低功耗模式。C-state是intelCPU处于空闲时的一种状态,CPU有几种电源模式,它们统称为“c状态”或“c模式”低功耗模式最初是在486DX4处理器中引入的。到目前为止,已经引入了更多的功耗模式,并且对每种模式进行了增强,以使CPU在这些低功耗模式下消耗更少的功率。CPU的每个状态都使用不同的电量,并且对应用程序性能的影响也不同。每当CPU内核处于空闲状态时,内置的节能逻辑就会启动,并尝试将内核从当前

    2022年10月27日
  • Java三大器之拦截器(Interceptor)的实现原理及代码示例「建议收藏」

    Java三大器之拦截器(Interceptor)的实现原理及代码示例「建议收藏」过滤器与拦截器的区别过滤器可以简单的理解为“取你所想取”,过滤器关注的是web请求;拦截器可以简单的理解为“拒你所想拒”,拦截器关注的是方法调用,比如拦截敏感词汇。4.1,拦截器是基于java反射机制来实现的,而过滤器是基于函数回调来实现的。(有人说,拦截器是基于动态代理来实现的)4.2,拦截器不依赖servlet容器,过滤器依赖于servlet容器。4.3,拦截器只对Action起作用,过滤器可以对所有请求起作用。4.4,拦截器可以访问Action上下文和值栈中的对象,过滤器不能。4

  • oracle用户修改密码权限_oracle提示表或视图不存在

    oracle用户修改密码权限_oracle提示表或视图不存在今天想要修改一个用户的密码,但是在执行完alteruser语句后,提示用户不存在。查看dba_users视图后,该用户的确是存在的,但是注意到一个细节是用户名是小写的,其他的用户名都是大写。在群内咨询过大神后,原来是在创建用户时,把用户名用双引号包起来了,如果没有用双引号,数据库会自动将用户名改为大写,但是用了双引号后,则保持小写。解决方法为,若创建过程用引号包起来,则在后续的使用过程中,也需要

  • HorizontalScrollView

    HorizontalScrollView一、概述、水平滚动条可以左右滑动可与ViewPager协同使用二、HorizontalScrollView里边只能放一个子元素可以放一个Layout布局对象来盛放多个元素里边可以设置指示器

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号