契约测试 No stubs or contracts were found for [XXX]问题解决

1、问题

最近在学习契约测试,用到的是spring-cloud-contract,网上有很多教程,便试着照葫芦画瓢的方式,来实现一遍。由提供者建立契约、生成存根,然后把存根交给消费方测试时,抛出了一个异常No stubs or contracts were found for [XXX],详细异常如下:

Caused by: org.eclipse.aether.resolution.ArtifactResolutionException: Could not find artifact com.contract:ContractTest:jar:stubs:0.0.1-SNAPSHOT
	at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:423) ~[spring-cloud-contract-shade-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifacts(DefaultArtifactResolver.java:225) ~[spring-cloud-contract-shade-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifact(DefaultArtifactResolver.java:202) ~[spring-cloud-contract-shade-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at shaded.org.eclipse.aether.internal.impl.DefaultRepositorySystem.resolveArtifact(DefaultRepositorySystem.java:257) ~[spring-cloud-contract-shade-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at org.springframework.cloud.contract.stubrunner.AetherStubDownloader.unpackedJar(AetherStubDownloader.java:185) ~[spring-cloud-contract-stub-runner-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	... 78 common frames omitted
Caused by: org.eclipse.aether.transfer.ArtifactNotFoundException: Could not find artifact com.contract:ContractTest:jar:stubs:0.0.1-SNAPSHOT
	at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:413) ~[spring-cloud-contract-shade-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	... 82 common frames omitted
	//省略...
	Caused by: java.lang.IllegalArgumentException: No stubs or contracts were found for [com.contract:ContractTest:0.0.1-SNAPSHOT:stubs] and the switch to fail on no stubs was set.
	at org.springframework.cloud.contract.stubrunner.CompositeStubDownloader.downloadAndUnpackStubJar(CompositeStubDownloaderBuilder.java:77) ~[spring-cloud-contract-stub-runner-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at org.springframework.cloud.contract.stubrunner.StubRunnerFactory.createStubsFromServiceConfiguration(StubRunnerFactory.java:75) ~[spring-cloud-contract-stub-runner-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at org.springframework.cloud.contract.stubrunner.BatchStubRunnerFactory.buildBatchStubRunner(BatchStubRunnerFactory.java:69) ~[spring-cloud-contract-stub-runner-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration.batchStubRunner(StubRunnerConfiguration.java:87) ~[spring-cloud-contract-stub-runner-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_151]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_151]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_151]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_151]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.2.5.RELEASE.jar:5.2.5.RELEASE]
	... 67 common frames omitted

根据异常可知道大致的意思是找不到存根。spring-cloud-contract我用的是2.2.2-RELEASE版本,消费方使用的存根是指向本地的maven仓库的,代码如下:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@AutoConfigureStubRunner(ids = {"com.contract:ContractTest:0.0.1-SNAPSHOT:stubs:8080"},
stubsMode = StubRunnerProperties.StubsMode.LOCAL)
public class TestConsumer {
}

然后我找了一下本地的仓库,发现是有ContractTest:0.0.1-SNAPSHOT-stubs.jar这个存根的,但为啥找不到呢?百思不得其姐…于是网上找答案,也很少相关的答案。于是只能“吃自己”了…

2、源码跟踪

网上找不到答案,那只能搜索一下源码了,因为我觉得问题应该是出在查找本地仓库那块了。因为StubsMode有三种情况,现在我用的是LOCAL。

	public enum StubsMode {
		CLASSPATH,//类路径
		LOCAL,//本地
		REMOTE,//远程
	}

于是我查找了StubsMode的引用,一路跟踪,最终找到了读取本地库的位置,就是这个localRepositoryDirectory方法

	public static RepositorySystemSession newSession(RepositorySystem system,
			boolean workOffline) {
		DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
		session.setOffline(workOffline);
		if (!workOffline) {
			session.setUpdatePolicy(RepositoryPolicy.UPDATE_POLICY_ALWAYS);
		}
		session.setChecksumPolicy(RepositoryPolicy.CHECKSUM_POLICY_WARN);
		String localRepositoryDirectory = localRepositoryDirectory(workOffline);//加载本地仓库的目录
		if (log.isDebugEnabled()) {
			log.debug("Local Repository Directory set to [" + localRepositoryDirectory
					+ "]. Work offline: [" + workOffline + "]");
		}
		LocalRepository localRepo = new LocalRepository(localRepositoryDirectory);
		session.setLocalRepositoryManager(
				system.newLocalRepositoryManager(session, localRepo));
		return session;
	}

深入这个方法,最后来到了"罪魁祸首"的地方—userSettings方法,这个方法里面有个读取系统变量的过程,就是fromSystemPropOrEnv(MAVEN_USER_SETTINGS_LOCATION),MAVEN_USER_SETTINGS_LOCATION常量值是org.apache.maven.user-settings,由上下文可以得知这个是配置maven仓库的setting.xml的路径,如果不设置这个路径,就会默认找user.home路径下的那个setting.xml。这我才想起,我的maven仓库并不是在user.home下的,而是另外建了个仓库地址!

	private static File userSettings() {
	    //MAVEN_USER_SETTINGS_LOCATION=org.apache.maven.user-settings
		String user = fromSystemPropOrEnv(MAVEN_USER_SETTINGS_LOCATION);
		if (user == null) {
			return new File(new File(System.getProperty("user.home")).getAbsoluteFile(),
					File.separator + ".m2" + File.separator + "settings.xml");
		}
		return new File(user);
	}

3、解决问题

得知了原因,问题就好解决了,只要把系统参数org.apache.maven.user-settings设置为正确的地址不就可以了?我用的是eclipse,在启动设置那里添加环境变量,来设置setting.xml的位置。
在这里插入图片描述
重启消费方,发现问题得解!!!

4、结论

从这个案例来看,我们不由得感叹阅读源码的重要性!源码不仅可以让你学习到很多思想,而且可以帮助你解决问题。网上可能有问题的解决方案,但是有时候你只知道怎么解决问题,但不知道为啥这样解决。源码可以让你从根本上去认知这套框架、系统,对于问题的解答,你也可以从最根源出着手!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章