契約測試 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、結論

從這個案例來看,我們不由得感嘆閱讀源碼的重要性!源碼不僅可以讓你學習到很多思想,而且可以幫助你解決問題。網上可能有問題的解決方案,但是有時候你只知道怎麼解決問題,但不知道爲啥這樣解決。源碼可以讓你從根本上去認知這套框架、系統,對於問題的解答,你也可以從最根源出着手!

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