摘要:退出擋板模式登錄驗(yàn)證碼,請(qǐng)不要對(duì)非本人透露。運(yùn)行之前寫的單元測(cè)試代碼輸入一個(gè)錯(cuò)誤的手機(jī)號(hào)進(jìn)入擋板模式登錄驗(yàn)證碼,請(qǐng)不要對(duì)非本人透露。
背景:
在項(xiàng)目開(kāi)發(fā)中,會(huì)有調(diào)用第三方接口的場(chǎng)景。當(dāng)開(kāi)發(fā)時(shí),對(duì)方不愿意提供測(cè)試服務(wù)器給我們調(diào)用,或者有的接口會(huì)按調(diào)用次數(shù)進(jìn)行計(jì)費(fèi)。當(dāng)聯(lián)調(diào)時(shí),第三方的測(cè)試服務(wù)器也可能會(huì)出現(xiàn)不穩(wěn)定,如果他們的服務(wù)掛了,我們就一直等著服務(wù)恢復(fù),那么這就相當(dāng)影響效率了。如果我們?cè)陂_(kāi)發(fā)時(shí),就定義一個(gè)擋板或者mock服務(wù),在發(fā)起調(diào)用時(shí),不直接調(diào)到第三方接口,而是調(diào)到我們自己的擋板代碼或者mock服務(wù),這樣就可以避免這些問(wèn)題了。
優(yōu)勢(shì):
擋板代碼,不需要侵入業(yè)務(wù)代碼,可以根據(jù)入?yún)⒆鲆恍﹦?dòng)態(tài)結(jié)果返回
不需要專門開(kāi)發(fā)一個(gè)擋板服務(wù),并且在每次啟動(dòng)客戶端都先啟動(dòng)擋板服務(wù)
可以自由選擇使用擋板還是Mock數(shù)據(jù)
Demo詳細(xì)代碼,已經(jīng)提交到Github,歡迎star
Demo地址: https://github.com/Seifon/Fei...
一、下面我就以一個(gè)第三方SMS短信接口來(lái)做演示:首先,我們寫一個(gè)Feign客戶端接口,正常調(diào)用第三方接口:
import cn.seifon.example.feignstubmock.dto.YunxunSmsReqDto; import cn.seifon.example.feignstubmock.dto.YunxunSmsRespDto; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; /** * @Author: Seifon * @Description: * @Date: Created in 10:24 2019/1/7 */ @FeignClient(name = "smsclient", url = "${sms.url}", primary = false) public interface YunxunSmsFeign { /** * * @param request * @return {"code":"0","failNum":"0","successNum":"1","msgId":"19012516213625881","time":"20190125162136","errorMsg":""} * @return {"code":"107","msgId":"","time":"20190125162358","errorMsg":"手機(jī)號(hào)碼格式錯(cuò)誤"} */ @PostMapping("/msg/variable/json") YunxunSmsRespDto send(@RequestBody YunxunSmsReqDto request); }
注意:@FeignClient注解里面的primary屬性一定要設(shè)置為false,這是為了防止在開(kāi)啟Feign擋板時(shí),出現(xiàn)多個(gè)Feign客戶端導(dǎo)致啟動(dòng)報(bào)錯(cuò)。
import cn.seifon.example.feignstubmock.dto.YunxunSmsReqDto; import cn.seifon.example.feignstubmock.dto.YunxunSmsRespDto; import cn.seifon.example.feignstubmock.feign.YunxunSmsFeign; import com.alibaba.fastjson.JSON; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class FeignStubMockApplicationTests { @Autowired private YunxunSmsFeign yunxunSmsFeign; @Test public void feignStubMockTest() { YunxunSmsReqDto yunxunSmsReqDto=new YunxunSmsReqDto(); yunxunSmsReqDto.setAccount("XXXXXXX"); yunxunSmsReqDto.setPassword("XXXXXXX"); yunxunSmsReqDto.setMsg("登錄驗(yàn)證碼:{$var},請(qǐng)不要對(duì)非本人透露。"); yunxunSmsReqDto.setParams("13011112222,123456"); yunxunSmsReqDto.setReport("true"); YunxunSmsRespDto send = yunxunSmsFeign.send(yunxunSmsReqDto); //打印結(jié)果 System.out.println(JSON.toJSON(send)); } }
2019-01-28 11:17:56.718 DEBUG 6920 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] ---> POST http://smssh1.253.com/msg/variable/json HTTP/1.1 2019-01-28 11:17:56.719 DEBUG 6920 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] Content-Type: application/json;charset=UTF-8 2019-01-28 11:17:56.720 DEBUG 6920 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] Content-Length: 160 2019-01-28 11:17:56.720 DEBUG 6920 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] 2019-01-28 11:17:56.721 DEBUG 6920 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] {"account":"XXXXXX","password":"XXXXXXX","msg":"登錄驗(yàn)證碼:{$var},請(qǐng)不要對(duì)非本人透露。","params":"17311112222,123456","report":"true"} 2019-01-28 11:17:56.721 DEBUG 6920 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] ---> END HTTP (160-byte body) 2019-01-28 11:17:56.958 DEBUG 6920 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] <--- HTTP/1.1 200 OK (236ms) 2019-01-28 11:17:56.960 DEBUG 6920 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] connection: keep-alive 2019-01-28 11:17:56.962 DEBUG 6920 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] content-length: 109 2019-01-28 11:17:56.963 DEBUG 6920 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] content-type: application/json;charset=UTF-8 2019-01-28 11:17:56.965 DEBUG 6920 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] date: Mon, 28 Jan 2019 03:17:56 GMT 2019-01-28 11:17:56.966 DEBUG 6920 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] 2019-01-28 11:17:56.971 DEBUG 6920 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] {"code":"0","failNum":"0","successNum":"1","msgId":"19012811175621982","time":"20190128111756","errorMsg":""} 2019-01-28 11:17:56.972 DEBUG 6920 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] <--- END HTTP (109-byte body) {"code":"0","failNum":"0","successNum":"1","msgId":"19012811175621982","time":"20190128111756","errorMsg":""}
此時(shí),我們可以根據(jù)日志,看到請(qǐng)求的地址也是第三方的url
2019-01-28 11:21:15.300 DEBUG 5288 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] ---> POST http://smssh1.253.com/msg/variable/json HTTP/1.1 2019-01-28 11:21:15.301 DEBUG 5288 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] Content-Type: application/json;charset=UTF-8 2019-01-28 11:21:15.302 DEBUG 5288 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] Content-Length: 152 2019-01-28 11:21:15.302 DEBUG 5288 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] 2019-01-28 11:21:15.303 DEBUG 5288 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] {"account":"XXXXX","password":"XXXXXXX","msg":"登錄驗(yàn)證碼:{$var},請(qǐng)不要對(duì)非本人透露。","params":"173,123456","report":"true"} 2019-01-28 11:21:15.303 DEBUG 5288 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] ---> END HTTP (152-byte body) 2019-01-28 11:21:15.470 DEBUG 5288 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] <--- HTTP/1.1 200 OK (165ms) 2019-01-28 11:21:15.471 DEBUG 5288 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] connection: keep-alive 2019-01-28 11:21:15.473 DEBUG 5288 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] content-length: 87 2019-01-28 11:21:15.474 DEBUG 5288 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] content-type: application/json;charset=UTF-8 2019-01-28 11:21:15.476 DEBUG 5288 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] date: Mon, 28 Jan 2019 03:21:15 GMT 2019-01-28 11:21:15.477 DEBUG 5288 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] 2019-01-28 11:21:15.483 DEBUG 5288 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] {"code":"107","msgId":"","time":"20190128112115","errorMsg":"手機(jī)號(hào)碼格式錯(cuò)誤"} 2019-01-28 11:21:15.484 DEBUG 5288 --- [ main] c.s.e.f.feign.YunxunSmsFeign : [YunxunSmsFeign#send] <--- END HTTP (87-byte body) {"code":"107","msgId":"","time":"20190128112115","errorMsg":"手機(jī)號(hào)碼格式錯(cuò)誤"}
當(dāng)我們知道了兩種情況下出現(xiàn)的結(jié)果,那么我們就可以模擬響應(yīng)結(jié)果啦。小技巧:我們可以先跟對(duì)方調(diào)接口,把各種響應(yīng)報(bào)文保存下來(lái),方便后面直接mock數(shù)據(jù)
二、接下來(lái)進(jìn)入擋板編寫環(huán)節(jié):import cn.seifon.example.feignstubmock.dto.YunxunSmsReqDto; import cn.seifon.example.feignstubmock.dto.YunxunSmsRespDto; import cn.seifon.example.feignstubmock.feign.YunxunSmsFeign; import org.apache.commons.lang3.RandomUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateFormatUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; import java.util.Date; /** * @Author: Seifon * @Description: * @Date: Created in 10:24 2019/1/7 */ @Primary //注意:需要在原Feign接口@FeignClient注解加入primary = false 屬性 @Component @ConditionalOnProperty(name = "feign-stub.yunxun.sms.mode", havingValue = "stub") public class YunxunSmsFeignStub implements YunxunSmsFeign { private static final Logger LOG = LoggerFactory.getLogger(YunxunSmsFeignStub.class); @Override public YunxunSmsRespDto send(YunxunSmsReqDto request) { YunxunSmsRespDto yunxunSmsRespDto = new YunxunSmsRespDto(); //模擬正常響應(yīng)結(jié)果 yunxunSmsRespDto.setCode("0"); yunxunSmsRespDto.setFailNum("0"); yunxunSmsRespDto.setSuccessNum("1"); yunxunSmsRespDto.setMsgId(String.valueOf(RandomUtils.nextLong(19000000000000000L, 19999999999999999L))); yunxunSmsRespDto.setTime(DateFormatUtils.format(new Date(), "yyyyMMddHHmmss")); yunxunSmsRespDto.setErrorMsg(""); String params = request.getParams(); String[] paramSplit = StringUtils.split(params, ","); if (paramSplit[0].length() != 11) { //模擬錯(cuò)誤響應(yīng)結(jié)果 yunxunSmsRespDto.setCode("107"); yunxunSmsRespDto.setMsgId(""); yunxunSmsRespDto.setErrorMsg("手機(jī)號(hào)碼格式錯(cuò)誤"); } return yunxunSmsRespDto; } }
注意:必須標(biāo)注@Primary注解,否則啟動(dòng)會(huì)報(bào)錯(cuò)。@ConditionalOnProperty的作用就是根據(jù)application.yaml配置的相關(guān)屬性,判斷是否注入Spring容器
sms: url: "http://smssh1.253.com" #yunxun:代表第三方系統(tǒng)名稱,sms:代表業(yè)務(wù)名稱,mode:代表Stub模式,url:代表mock服務(wù)地址 feign-stub: yunxun: sms: mode: "stub"
import com.alibaba.fastjson.JSON; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; /** * @Author: Seifon * @Description: * @Date: Created in 10:24 2019/1/7 */ @Aspect @Component public class FeignStubAspect { private static final Logger LOG = LoggerFactory.getLogger(FeignStubAspect.class); @Pointcut("execution(* cn.seifon.example.feignstubmock..stub.*.*(..))") public void pointCut(){} @Around("pointCut()") public Object around(ProceedingJoinPoint pjp){ String name = StringUtils.join(pjp.getTarget().getClass().getName(), ".", pjp.getSignature().getName()); LOG.info("-----【{}】---- 進(jìn)入擋板模式... request: 【{}】", name, JSON.toJSON(pjp.getArgs())); try { Object proceed = pjp.proceed(); LOG.info("-----【{}】---- 退出擋板模式... request: 【{}】, response: 【{}】", name, JSON.toJSON(pjp.getArgs()), JSON.toJSON(proceed)); return proceed; } catch (Throwable e) { e.printStackTrace(); } return null; } }
2019-01-28 11:32:51.255 INFO 7488 --- [ main] c.s.e.f.aspect.FeignStubAspect : -----【cn.seifon.example.feignstubmock.feign.stub.YunxunSmsFeignStub.send】---- 進(jìn)入擋板模式... request: 【[{"msg":"登錄驗(yàn)證碼:{$var},請(qǐng)不要對(duì)非本人透露。","password":"XXXXXXX","report":"true","params":"13011112222,123456","account":"XXXXXXX"}]】 2019-01-28 11:32:51.975 INFO 7488 --- [ main] c.s.e.f.aspect.FeignStubAspect : -----【cn.seifon.example.feignstubmock.feign.stub.YunxunSmsFeignStub.send】---- 退出擋板模式... request: 【[{"msg":"登錄驗(yàn)證碼:{$var},請(qǐng)不要對(duì)非本人透露。","password":"XXXXXXX","report":"true","params":"13011112222,123456","account":"XXXXXXX"}]】, response: 【{"code":"0","failNum":"0","successNum":"1","msgId":"19148964234899564","time":"20190128113251","errorMsg":""}】 {"code":"0","failNum":"0","successNum":"1","msgId":"19148964234899564","time":"20190128113251","errorMsg":""}
2019-01-28 11:35:27.177 INFO 15204 --- [ main] c.s.e.f.aspect.FeignStubAspect : -----【cn.seifon.example.feignstubmock.feign.stub.YunxunSmsFeignStub.send】---- 進(jìn)入擋板模式... request: 【[{"msg":"登錄驗(yàn)證碼:{$var},請(qǐng)不要對(duì)非本人透露。","password":"XXXXXXX","report":"true","params":"130,123456","account":"XXXXXXX"}]】 2019-01-28 11:35:27.900 INFO 15204 --- [ main] c.s.e.f.aspect.FeignStubAspect : -----【cn.seifon.example.feignstubmock.feign.stub.YunxunSmsFeignStub.send】---- 退出擋板模式... request: 【[{"msg":"登錄驗(yàn)證碼:{$var},請(qǐng)不要對(duì)非本人透露。","password":"XXXXXXX","report":"true","params":"130,123456","account":"XXXXXXX"}]】, response: 【{"code":"107","failNum":"0","successNum":"1","msgId":"","time":"20190128113527","errorMsg":"手機(jī)號(hào)碼格式錯(cuò)誤"}】 {"code":"107","failNum":"0","successNum":"1","msgId":"","time":"20190128113527","errorMsg":"手機(jī)號(hào)碼格式錯(cuò)誤"}
以上代碼就完成了一個(gè)stub擋板功能,可有時(shí)候,我們已經(jīng)拿到第三方接口的返回報(bào)文,并切不想去寫一大段Stub代碼。那么這個(gè)時(shí)候,我們就可以選擇下面的Mock方式去完成我們的功能。
三、接下來(lái)進(jìn)入Mock環(huán)節(jié):參看官網(wǎng):http://nodejs.cn/
npm install -g mock-json-server
{ "/msg/variable/json": { "post": { "code":"0", "failNum":"0", "successNum":"1", "msgId":"19012516213625881", "time":"20190125162136", "errorMsg":"" } } }
mock-json-server {path}/data.json --port=1240 {path}替換為存放data.json的絕對(duì)路徑
JSON Server running at http://localhost:1240/
mock-json-server具體使用文檔,請(qǐng)參考:https://www.npmjs.com/package...
import cn.seifon.example.feignstubmock.feign.YunxunSmsFeign; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; /** * @Author: Seifon * @Description: * @Date: Created in 10:24 2019/1/7 */ @Primary //注意:需要在原Feign接口@FeignClient注解加入primary = false 屬性 @Component @ConditionalOnProperty(name = "feign-stub.yunxun.sms.mode", havingValue = "mock") @FeignClient(name = "smsclient-mock", url = "${feign-stub.yunxun.sms.mockUrl}" ,path = "/") public interface YunxunSmsFeignMock extends YunxunSmsFeign { }
注意:必須標(biāo)注@Primary注解,否則啟動(dòng)時(shí)會(huì)報(bào)錯(cuò)。@FeignClient里的name屬性不能跟原Feign接口名稱相同,如果相同會(huì)啟動(dòng)報(bào)錯(cuò)。@ConditionalOnProperty的作用就是根據(jù)application.yaml配置的相關(guān)屬性,判斷是否注入Spring容器
sms: url: "http://smssh1.253.com" #生產(chǎn)環(huán)境請(qǐng)勿添加此配置。mode說(shuō)明:""-不開(kāi)啟, "mock"-mock模式, "stub"-stub模式。url說(shuō)明:只有mock模式需要配置調(diào)試url。fund為第三方機(jī)構(gòu),repayment是業(yè)務(wù)名稱 #yunxun:代表第三方系統(tǒng)名稱,sms:代表業(yè)務(wù)名稱,mode:代表?yè)醢迥J剑瑄rl:代表mock服務(wù)地址 feign-stub: yunxun: sms: mode: "mock" mockUrl: "http://localhost:1240"
import com.alibaba.fastjson.JSON; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; /** * @Author: Seifon * @Description: * @Date: Created in 10:24 2019/1/7 */ @Aspect @Component public class FeignMockAspect { private static final Logger LOG = LoggerFactory.getLogger(FeignMockAspect.class); @Pointcut("execution(* cn.seifon.example.feignstubmock..mock.*.*(..))") public void pointCut(){} @Around("pointCut()") public Object around(ProceedingJoinPoint pjp){ String name = StringUtils.join(pjp.getTarget().getClass().getName(), ".", pjp.getSignature().getName()); LOG.info("-----【{}】---- 進(jìn)入Mock模式... request: 【{}】", name, JSON.toJSON(pjp.getArgs())); try { Object proceed = pjp.proceed(); LOG.info("-----【{}】---- 退出Mock模式... request: 【{}】, response: 【{}】", name, JSON.toJSON(pjp.getArgs()), JSON.toJSON(proceed)); return proceed; } catch (Throwable e) { e.printStackTrace(); } return null; } }
2019-01-28 16:16:35.567 INFO 8976 --- [ main] c.s.e.f.aspect.FeignMockAspect : -----【com.sun.proxy.$Proxy95.send】---- 進(jìn)入Mock模式... request: 【[{"msg":"登錄驗(yàn)證碼:{$var},請(qǐng)不要對(duì)非本人透露。","password":"XXXXXXX","report":"true","params":"13011112222,123456","account":"XXXXXXX"}]】 2019-01-28 16:16:35.934 DEBUG 8976 --- [ main] c.s.e.f.feign.mock.YunxunSmsFeignMock : [YunxunSmsFeignMock#send] ---> POST http://localhost:1240/msg/variable/json HTTP/1.1 2019-01-28 16:16:35.935 DEBUG 8976 --- [ main] c.s.e.f.feign.mock.YunxunSmsFeignMock : [YunxunSmsFeignMock#send] Content-Type: application/json;charset=UTF-8 2019-01-28 16:16:35.936 DEBUG 8976 --- [ main] c.s.e.f.feign.mock.YunxunSmsFeignMock : [YunxunSmsFeignMock#send] Content-Length: 152 2019-01-28 16:16:35.936 DEBUG 8976 --- [ main] c.s.e.f.feign.mock.YunxunSmsFeignMock : [YunxunSmsFeignMock#send] 2019-01-28 16:16:35.937 DEBUG 8976 --- [ main] c.s.e.f.feign.mock.YunxunSmsFeignMock : [YunxunSmsFeignMock#send] {"account":"XXXXXXX","password":"XXXXXXX","msg":"登錄驗(yàn)證碼:{$var},請(qǐng)不要對(duì)非本人透露。","params":"13011112222,123456","report":"true"} 2019-01-28 16:16:35.937 DEBUG 8976 --- [ main] c.s.e.f.feign.mock.YunxunSmsFeignMock : [YunxunSmsFeignMock#send] ---> END HTTP (152-byte body) 2019-01-28 16:16:36.021 DEBUG 8976 --- [ main] c.s.e.f.feign.mock.YunxunSmsFeignMock : [YunxunSmsFeignMock#send] <--- HTTP/1.1 200 OK (82ms) 2019-01-28 16:16:36.021 DEBUG 8976 --- [ main] c.s.e.f.feign.mock.YunxunSmsFeignMock : [YunxunSmsFeignMock#send] access-control-allow-origin: * 2019-01-28 16:16:36.022 DEBUG 8976 --- [ main] c.s.e.f.feign.mock.YunxunSmsFeignMock : [YunxunSmsFeignMock#send] connection: keep-alive 2019-01-28 16:16:36.023 DEBUG 8976 --- [ main] c.s.e.f.feign.mock.YunxunSmsFeignMock : [YunxunSmsFeignMock#send] content-length: 109 2019-01-28 16:16:36.023 DEBUG 8976 --- [ main] c.s.e.f.feign.mock.YunxunSmsFeignMock : [YunxunSmsFeignMock#send] content-type: application/json; charset=utf-8 2019-01-28 16:16:36.024 DEBUG 8976 --- [ main] c.s.e.f.feign.mock.YunxunSmsFeignMock : [YunxunSmsFeignMock#send] date: Mon, 28 Jan 2019 08:16:36 GMT 2019-01-28 16:16:36.024 DEBUG 8976 --- [ main] c.s.e.f.feign.mock.YunxunSmsFeignMock : [YunxunSmsFeignMock#send] etag: W/"6d-XqhLoZB8r6IRF2Lb6CWoIVVNhIQ" 2019-01-28 16:16:36.025 DEBUG 8976 --- [ main] c.s.e.f.feign.mock.YunxunSmsFeignMock : [YunxunSmsFeignMock#send] x-content-type-options: nosniff 2019-01-28 16:16:36.026 DEBUG 8976 --- [ main] c.s.e.f.feign.mock.YunxunSmsFeignMock : [YunxunSmsFeignMock#send] x-powered-by: Express 2019-01-28 16:16:36.027 DEBUG 8976 --- [ main] c.s.e.f.feign.mock.YunxunSmsFeignMock : [YunxunSmsFeignMock#send] 2019-01-28 16:16:36.030 DEBUG 8976 --- [ main] c.s.e.f.feign.mock.YunxunSmsFeignMock : [YunxunSmsFeignMock#send] {"code":"0","failNum":"0","successNum":"1","msgId":"19012516213625881","time":"20190125162136","errorMsg":""} 2019-01-28 16:16:36.030 DEBUG 8976 --- [ main] c.s.e.f.feign.mock.YunxunSmsFeignMock : [YunxunSmsFeignMock#send] <--- END HTTP (109-byte body) 2019-01-28 16:16:36.227 INFO 8976 --- [ main] c.s.e.f.aspect.FeignMockAspect : -----【com.sun.proxy.$Proxy95.send】---- 退出Mock模式... request: 【[{"msg":"登錄驗(yàn)證碼:{$var},請(qǐng)不要對(duì)非本人透露。","password":"XXXXXXX","report":"true","params":"13011112222,123456","account":"XXXXXXX"}]】, response: 【{"code":"0","failNum":"0","successNum":"1","msgId":"19012516213625881","time":"20190125162136","errorMsg":""}】 {"code":"0","failNum":"0","successNum":"1","msgId":"19012516213625881","time":"20190125162136","errorMsg":""}
說(shuō)明:此時(shí)我們根據(jù)日志,會(huì)發(fā)現(xiàn)feign調(diào)用的url已經(jīng)變?yōu)槲覀兊腗ock服務(wù)地址了。同理,如果要返回失敗結(jié)果,只需要修改data.json文件,再次調(diào)用后,即可得到我們想要的結(jié)果了。
四、結(jié)語(yǔ):如果有什么需要改進(jìn)的地方,或者不正確的地方,請(qǐng)?jiān)谠u(píng)論里面提出并指正。謝謝!
Demo詳細(xì)代碼,已經(jīng)提交到Github,歡迎star
Demo地址: https://github.com/Seifon/Fei...
項(xiàng)目結(jié)構(gòu),如圖:
原文地址:http://www.seifon.cn/2019/01/...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/73234.html
摘要:完成后一定要否則會(huì)影響其他的測(cè)試的作用在于可以監(jiān)視一個(gè)函數(shù)被調(diào)用的情況。在中用于對(duì)一個(gè)的活動(dòng)進(jìn)行監(jiān)視。而出的收到了數(shù)據(jù)或是調(diào)用并沒(méi)有真正執(zhí)行,一切針對(duì)的調(diào)用都是假的。對(duì)相關(guān)的測(cè)試也提供了模擬功能。 Sinon.js是個(gè)測(cè)試輔助工具,在為Node程序?qū)憸y(cè)試時(shí)可能可以派上用場(chǎng)。 在測(cè)試領(lǐng)域有這么幾個(gè)基本名詞:spy, stub, mock,這三個(gè)概念都是測(cè)試所用到的手段。Sinon.js就...
摘要:基本上,測(cè)試金字塔描述你應(yīng)該編寫單元測(cè)試集成測(cè)試和端到端測(cè)試。集成測(cè)試要比端到端測(cè)試多,單元測(cè)試甚至要更多一些。應(yīng)用程序單元測(cè)試編寫單元測(cè)試,是為了看看給定的模塊單元是否工作。 本文轉(zhuǎn)載自:眾成翻譯譯者:網(wǎng)絡(luò)埋伏紀(jì)事鏈接:http://www.zcfy.cc/article/1754原文:https://blog.risingstack.com/node-hero-node-js-un...
摘要:而且,構(gòu)造函數(shù)不應(yīng)該包含行為,所以沒(méi)有值得測(cè)試的東西。一旦一個(gè)被創(chuàng)建了,你測(cè)試它的不為空因?yàn)槟阒罉?gòu)造函數(shù)創(chuàng)建了一個(gè)新的并將它賦給了變量。現(xiàn)在為類的構(gòu)造函數(shù)編寫的測(cè)試出問(wèn)題了,即便類運(yùn)行良好,但并沒(méi)有包括。 在研究了有關(guān)測(cè)試的相關(guān)內(nèi)容,發(fā)現(xiàn)有些被忽略掉的很明顯的問(wèn)題。 1、為什么需要測(cè)試 從積極的方面來(lái)說(shuō),寫自動(dòng)化測(cè)試的優(yōu)勢(shì)如下: 使重構(gòu)更簡(jiǎn)單 —— 你可以自信的修改實(shí)現(xiàn)細(xì)節(jié),而不用...
閱讀 1369·2021-10-09 09:44
閱讀 1448·2021-09-28 09:36
閱讀 16000·2021-09-22 15:55
閱讀 1253·2021-09-22 15:45
閱讀 2207·2021-09-02 09:48
閱讀 2793·2019-08-29 17:19
閱讀 2306·2019-08-29 10:54
閱讀 918·2019-08-23 18:40