-
今天可爱的版主我为大家带来软件开发中的android 大家熟知android的作用给我们的生活带来的便利,为大家提供下sdk中的native方法 单元测试:元测试就是针对最小的功能单元编写测试代码。Java程序最小的功能单元是方法,因此,对Java程序进行单元测试就是针对单个Java方法的测试。 对于AndroidSDK来说,我们的单元测试,主要是针对测试人员测试不到的一些内部逻辑方法。同时,可以在转测之前让程序自动运行自测。一、单元测试常用的覆盖率量化标准一般来说路径覆盖率>判定覆盖率>语句覆盖率1、语句覆盖/行覆盖这是一种比较常用的指标,度量的是被测试代码中所有可执行语句是否被执行到,单独一行的花括号{}也常常被统计进去。语句覆盖只管覆盖代码中的可执行语句,但是没有考虑各种分支的组合,常常被指为“最弱的覆盖”。举个例子,被测试代码如下:int foo(int a, int b) { return a / b;}只要设计如下一组测试用例,就可以达到覆盖率100%:TeseCase: a = 10, b = 5但是这里有一个比较简单的bug,当b=0的时候,程序就会抛出异常。所以语句覆盖率这个量化标准,并不能直接的表示代码的功能性完整。2、判定覆盖/分支覆盖它度量程序中每一个判定的分支是被测试到了,容易与条件覆盖混淆,所以在条件覆盖中对比说明。3、条件覆盖率它度量判定中的每个子表达式结果true和false是否被测试到了。举一个例子来区分条件覆盖和判定覆盖,被测试代码如下:int foo(int a, int b) { if (a < 10 || b < 10) { // 判定 return 0; // 分支一 } else { return 1; // 分支二 }}设计判定覆盖案例时,我们只需要考虑判定结果为true和false两种情况,因此,我们设计如下的案例就能达到判定覆盖率100%:TestCaes1: a = 5, b = 任意数字 // 覆盖了分支一TestCaes2: a = 15, b = 15 // 覆盖了分支二设计条件覆盖案例时,我们需要考虑判定中的每个条件表达式结果,为了覆盖率达到100%,我们设计了如下的案例:TestCase1: a = 5, b = 5 // true, trueTestCase4: a = 15, b = 15 // false, false通过上面的例子,我们应该很清楚了判定覆盖和条件覆盖的区别。需要特别注意的是:条件覆盖不是将判定中的每个条件表达式的结果进行排列组合,而是只要每个条件表达式的结果true和false测试到了就OK了。因此,我们可以这样推论:完全的条件覆盖并不能保证完全的判定覆盖。比如上面的例子,假如我设计的案例为:TestCase1: a = 5, b = 15 // true, false 分支一TestCase1: a = 15, b = 5 // false, true 分支一我们看到,虽然我们完整的做到了条件覆盖,但是我们却没有做到完整的判定覆盖,我们只覆盖了分支一。4、路径覆盖/断言覆盖它度量了是否函数的每一个分支都被执行了。举个例子区分一下四种覆盖方式,被测试代码如下:int foo(int a, int b) { int nReturn = 0; if (a < 10) { // 分支一 nReturn += 1; } if (b < 10) { // 分支二 nReturn += 10; } return nReturn;}a.语句覆盖TestCase a = 5, b = 5 // nReturn = 11b.判定覆盖TestCase1 a = 5, b = 5 // nReturn = 11TestCase2 a = 15, b = 15 // nReturn = 0c.条件覆盖TestCase1 a = 5, b = 15 // nReturn = 1TestCase2 a = 15, b = 5 // nReturn = 10d.路径覆盖TestCase1 a = 5, b = 5 // nReturn = 0TestCase2 a = 15, b = 5 // nReturn = 1TestCase3 a = 5, b = 15 // nReturn = 10TestCase4 a = 15, b = 15 // nReturn = 11二、工具选择:JUnit+PowerMockito JUnit只能mock方法,不能mock实例;并且JUnit使用本地JVM提供运行环境,如果测试的单元依赖了Android框架(或者测试类依赖于其他外部类的情况),比如用到了Android中的Context、SP类的一些方法,本地JVM将无法提供这样的环境,所以我们一般会结合其他开源Mock框架共同完成单元测试。 Android(Java)常用的单元测试开源库一般是Mockito模拟框架,Mockito可以Mock对象,同时可以模拟安卓的运行环境,以及一些service访问返回等。但是,Mokito只能模拟public的方法(网上有通过反射修改private方法access来实现mock方法的,感觉比较麻烦)比较适用于大多标准的单元测试case。 PowerMockito是一个扩展了其他mock框架的、功能更强大的框架。与Mockito的用处总体上一样,都是为了mock外部的、不容易构造的环境,但是PowerMokito可以用于解决更多复杂的情况,PowerMockito可以对private/final/static的方法进行mock,同时PowerMockito支持Mockito和EasyMock。三、常用方法模糊匹配想测试一个方法,但是不想传入精确的值,这时候可以使用Mockito.antInt(),Mockito.anyString()方法。比如我们的日志功能Log.d(tag,msg),我们想mock这个方法,不论传入的tag和msg是什么字符串,就可以使用这个方法,后面的方法会有具体的代码示例。模拟static方法代码中比较常见的就是自定义的static日志方法,Log.d(tagStr, mesStr),测试一个方法的时候,如果里面有日志输出,可以在方法调用之前,mock当调用日志方法的时候,什么都不做,代码如下:PowerMockito.mockStatic(Log.class); try { PowerMockito.doNothing().when(Log.class, "d", Mockito.anyString(), Mockito.anyString()); } catch (Exception e) { e.printStackTrace(); }如果是有返回值得static方法,则可能用PowerMockito.doReturn(mockValue).when()或者PowerMockito.when().thenReturn(mockValue)来模拟。如果使用了mockStatic方法,需要在class前面加注解,代码如下:@RunWith(PowerMockRunner.class) @PrepareForTest({Log.class})理论上来说,@PrepareForTests注解也可以放在对应的测试方法上方,但是有时候会报错,所以最好还是统一放在class前面,里面包含了所有需要mock的class。private方法的单元测试基本实现方式是通过反射,将private方法的accessible设为true,之后与正常的public方法的单元测试方法相同。比如待测试类Tested中有待测试方法如下:private long getPrivateMethod(SelfClass self) { long result = -1; if (self.methodA()) { result = 1; } return result; }单元测试方法中,反射代码如下:Tested test = new Tested(); Method getPrivate = test.getClass().getDeclaredMethod("getPrivateMethod", Tested.class); getPrivate.setAccessible(true);native方法的单元测试native方法的单元测试从运行环境上也是有两种实现方式:本地单元测试和真机(仪器化)测试。本地单元测试,运行在JVM上,需要依赖于Espresso等模拟安卓环境的工具,好处是运行速度较快,但是仿真度稍差,同时比较麻烦。仪器化测试运行在真机上,好处是仿真度高,同时比较方便,缺点是,仪器化测试除了打包本身的apk外,还会生成test-apk(SDK的话,只会生成test-apk),因为要生成apk,所以速度比较慢。仪器化测试需要将测试代码写在androidTest目录下,如果native方法依赖于本地的so库,则需要以相同的目录结构,在androidTest目录下放置so文件。仪器化测试一般用的是Android自带的AndroidJUnitRunner,不过目前不支持PowerMockito,依赖隔绝不太方便,所以建议尽量使用本地测试,对于依赖于不好模拟的安卓环境,或者耗时较高的文件读写等方法,再使用真机测试。四、IDEA(AndroidStudio)配置依赖配置build.gradle文件:dependencies {......testImplementation 'junit:junit:4.12'testImplementation 'org.mockito:mockito-core:2.8.0'testImplementation 'org.powermock:powermock-module-junit4:1.7.1'testImplementation 'org.powermock:powermock-module-junit4-rule:1.7.1'testImplementation 'org.powermock:powermock-api-mockito2:1.7.1'androidTestImplementation 'com.android.support:support-annotations:24.0.0'androidTestImplementation 'com.android.support.test:runner:0.5'......}需要注意PowerMockito和Mockito的版本对应,否则可能会报java.lang.ClassNotFoundException: org.mockito.exceptions.Reporter。testImplementation 'org.powermock:powermock-api-mockito2:1.7.1'上面的配置需要注意是mockito2。(之前每次使用PowerMockito.doXXX.when()的时候都会报错,升级版本之后就没有了,不确定是不是因为版本的问题,还是这个2的问题)五、覆盖率检测及报告生成:JaCoCo六、可能出现的问题UnfinishedStubbingException1、条件里面嵌套的方法比较多网上的示例基本都是说,when里面的条件比较复杂,就会嵌套调用了方法,可以把方法放到外面来做,网上举的例子错误代码如下:@Testpublic myTest() { MyMainModel mainModel = Mockito.mock(MyMainModel.class); Mockito.when(mainModel.getList()).thenReturn(getSomeList()); }修改后代码为:@Testpublic myTest() { MyMainModel mainModel = Mockito.mock(MyMainModel.class); List<SomeModel> someModelList = getSomeList(); Mockito.when(mainModel.getList()).thenReturn(someModelList);}网上基本上查到的答案都是上面那个解决方案,不过实际原因可能比较多,还是以Log.d(tag, msg)方法举例:2、条件语句格式的问题PowerMockito.doNothing().when()或者PowerMockito.doReturn.when()的时候,when里面的条件写法也可能导致报错,还是以Log.d(tag, msg)举例:// 错误示例PowerMockito.doNothing().when(log.d(tag, msg));PowerMockito.doNothing().when(log).d(tag, msg);PowerMockito.doNothing().when(log.class, "d", String.class, String.class);// 正确示例PowerMockito.doNothing().when(Log.class, "d", Mockito.anyString(), Mockito.anyString());PowerMockito.doNothing().when(Log.class, "d", "tag", "message");// 这个写法在方法里面写没有问题,但是写在@Before或者@BeforeClass里面就会报错,不知道为啥PowerMockito.doNothing().when(Log.class);类要用class对象而不是具体的实例;通过String的格式传入方法名,此处需要try-catch,因为可能找不到这个方法名的方法;参数要传入具体的实例,或者模糊替代,否则会报找不到对应的方法的错误。找不到Declared的方法参考UnfinishedStubbingException里面条件语句格式问题。
-
华为云会议服务为开发者提供Windows、Android、iOS的客户端SDK,方便开发者将华为云会议的音频会议、视频会议、桌面共享能力快速集成到自己的应用中。华为云会议的客户端SDK已经实现了会议中UI界面,包括会场画面显示,会议控制功能,桌面共享等,开发者只需要调用少量接口即可完成华为云会议能力的集成。客户端SDK已经提供的主要UI如下(以Windows SDK为例,其他平台的SDK能力相同,只是界面布局有差异):接下来我就来描述个步聚:1:会议中的主界面2:桌面共享界面3:会议来电界面如还是有疑问,可以点击链接进入看更直观的图文搭配描述,更清晰具体!!—— https://support.huaweicloud.com/sdkreference-meeting/meeting_22_0001.html
-
问题目录如下,详见附件:
-
eSDK/APIG配套到SMC19.1SPC100,后续将推出JAVA SDK,将不需要再安装eSDK/APIG平台;若要使用SMC全量功能接口,建议使用SMC原生接口,请了解这些,根据项目需求选择开发方案,谢谢! SMC API(SMC原生接口开发,第五章节为开发示例)https://support.huawei.com/enterprise/zh/doc/EDOC1100101272?idPath=22658044%7C21781198%7C21781768%7C21781990%7C6644576 APIG(需要一**立服务器安装,裸金属、FC6.5、HCS三种服务器平台具备安装欧拉镜像系统硬件能力,裸金属请勿使用2288HV5服务器)1、eSDK EC 下载https://support.huawei.com/enterprise/zh/uc-c-common/esdk-ec-pid-22190398/software/250798008?idAbsPath=fixnode01%7C22658044%7C21781198%7C221903982 、欧拉系统 和APIG平台安装指南https://support.huawei.com/enterprise/zh/doc/EDOC1100115777?idPath=22658044%7C21781198%7C22190398https://support.huawei.com/enterprise/zh/doc/EDOC1100075608?idPath=22658044%7C7919788%7C9856606%7C21734214%7C23505807### 3、eSDK CloudVC 19.1.3 服务端API安装配置指南https://support.huawei.com/enterprise/zh/doc/EDOC1100115778?idPath=22658044%7C21781198%7C22190398 4、开发指南https://support.huawei.com/enterprise/zh/doc/EDOC1100115785?idPath=22658044%7C21781198%7C22190398 5、接口参考JAVA Nativehttps://support.huawei.com/enterprise/zh/doc/EDOC1100115781?idPath=22658044%7C21781198%7C22190398 SOAP:https://support.huawei.com/enterprise/zh/doc/EDOC1100115782?idPath=22658044%7C21781198%7C22190398 6、Demohttps://github.com/Huawei/eSDK_TP_APIG_Demo_Native eSDK server(可与SMC合设)1、eSDK 软件下载https://support.huawei.com/enterprise/zh/uc-c-common/esdk-tp-pid-21057343/software/23873953?idAbsPath=fixnode01%7C22658044%7C21781198%7C210573432、开发指南Java Nativehttps://support.huawei.com/enterprise/zh/doc/EDOC1100067410?idPath=22658044%7C21781198%7C21057343SOAPhttps://support.huawei.com/enterprise/zh/doc/EDOC1100012581?idPath=22658044%7C21781198%7C210573433、接口文档Java nativehttps://support.huawei.com/enterprise/zh/doc/EDOC1100067471?idPath=22658044%7C21781198%7C21057343SOAPhttps://support.huawei.com/enterprise/zh/doc/EDOC1100012580?idPath=22658044%7C21781198%7C210573434、安装配置指南https://support.huawei.com/enterprise/zh/doc/EDOC1100012579?idPath=22658044%7C21781198%7C21057343
-
请问怎样通过内网将OBS上面的文件下载并打包,然后再通过内网打包再上传到OBS上
-
-
最近几个月,我的变化其实还蛮大的,从一个被实习生“无视”的“前浪”,转变成了不仅能够解决技术问题还能解决业务问题(顺手还能帮实习生解决恋爱问题)的“前辈”。前面几期故事记录了我的高光时刻,有兴趣可以点击前文查看(https://bbs.huaweicloud.com/forum/forum-1104-1.html)。 公司的短视频项目上线之后一直不温不火,老板挺着急,运营部提出要在6月底组织一次千人直播带货活动,邀请1千个主播同时在短视频平台上开直播,拉用户和流量。 千人同时在线直播,短视频平台的目标访问量在百万级以上,需要技术部门保证高并发流量下服务器的稳定。这个好办,华为云弹性云服务器是可以随时扩容的,经过部门研究,我们给出的技术方案是临时创建100台云虚拟机来支撑这次活动。 这个任务又光荣地落到了我的身上,谁让我是公司公认的云服务器专家呢…可离直播活动落地只有一个星期的时间了,还要留出时间进行压测。“通过API可以批量处理弹性云服务器,但我现在一个个接口封装也来不及啊!而且根据我的经验,还得提前做好随时扩容的准备,能够支持比预估目标更高的流量,得赶紧想想除了API还有什么可以用……”我心里有点着急了。 习惯性地打开华为云官网,在首页发呆了1分钟,一道灵光闪过:操作简单,可以快速控制批量资源,这可不就是SDK的特性吗!说来就来,我很快就有了思路:先快速创建100台按需计费的弹性云服务器作为直播支撑,在直播完成后,再对这些弹性云服务器进行释放。 打开API Explorer(https://apiexplorer.developer.huaweicloud.com/apiexplorer/overview?utm_source=apiwz&utm_medium=read )快速浏览,确认我需要用到的接口是CreatePostPaidServers 、 ListServerDetails 和DeleteServers。 万万没想到,这个设计还真起到了救急的作用! 直播开始前1个小时,运营部门突然反馈,这次活动的推广效果大大超出预期,峰值流量可能是预期目标的10倍!这将给网站访问带来很大的压力,老大给我打电话问我有没有办法处理。 这当然难不住我了,因为提前准备了技术方案,在直播过程中随着访问量的变化,随时批量调整服务器的配置,完美保障了直播的进行,最后在10倍于目标值的访问量下,依然没有出现任何卡顿/延迟的情况。 活动结束后,我又开始了疯狂输出,将SDK的配置方法写在了文档里: 一、前置条件:获取必填参数 1. 华为云SDK的认证方式为AK/SK认证,可以在华为云控制台”我的凭证-访问密钥”页面上创建和查看AK/SK。更多信息请查看访问密钥(https://support.huaweicloud.com/usermanual-ca/zh-cn_topic_0046606340.html)。 2. 准备接口的必填参数PS:在华为云控制台-镜像服务IMS中可快速获取公共镜像相应的ID服务器配置详情:l 区域:华北-北京一 - cn-north-1l 可用区:可用区1 - cn-north-1al 规格:通用计算增强型 - c3.large.2l 镜像:Windows Server 2019数据中心版 64 位简体中文 - fb48d5c7-8718-489a-9273-d3e0e09c84d7l 服务器名:任意指定 - 如 "live-stream”l 系统盘类型:普通 IO 磁盘 – "SATA"l 虚拟私有云 ID(VPC ID):可获取当前账号在北京一区域中默认的 VPC ID,若没有默认 VPC 则新建l 网卡信息:可获取当前账号在北京一区域中默认 PC / 新建 VPC 下的子网 IDl 允许重名:当批量创建弹性云服务器时,云服务器名称是否允许重名,当count大于1的时候该参数生效 - false 二、实战演练PS:指南:https://github.com/huaweicloud/huaweicloud-sdk-java-v3/blob/master/README_CN.md 1. 新建maven项目,导入SDK的maven依赖<!-- add dependencies in pom.xml --><dependency> <groupId>com.huaweicloud.sdk</groupId> <artifactId>huaweicloud-sdk-core</artifactId> <version>[3.0.1-beta, 3.1.0-beta)</version></dependency><dependency> <groupId>com.huaweicloud.sdk</groupId> <artifactId>huaweicloud-sdk-ecs</artifactId> <version>[3.0.1-beta, 3.1.0-beta)</version></dependency>2. 批量创建弹性云服务器Demoimport com.huaweicloud.sdk.core.auth.BasicCredentials;import com.huaweicloud.sdk.core.http.HttpConfig;import com.huaweicloud.sdk.ecs.v2.EcsClient;import com.huaweicloud.sdk.ecs.v2.model.*; import java.util.LinkedList;import java.util.List; public class TestCreateEcs { public static void main(String[] args) { String ak = "{your ak string}"; String sk = "{your sk string}"; String projectId = "{your project id}"; String endpoint = "https://ecs.cn-north-1.myhuaweicloud.com"; HttpConfig config = HttpConfig.getDefaultHttpConfig().withIgnoreSSLVerification(true); BasicCredentials credentials = new BasicCredentials().withAk(ak).withSk(sk).withProjectId(projectId); EcsClient ecsClient = EcsClient.newBuilder().withCredential(credentials).withEndpoint(endpoint).withHttpConfig(config).build(); // 确认创建虚拟机的必填参数 String az = "cn-north-1a"; String flavorRef = "s3.medium.2"; String imageRef = "fb48d5c7-8718-489a-9273-d3e0e09c84d7"; String name = "live-stream"; String vpcId = "{you vpc id}"; // 网卡信息 PostPaidServerNic nic = new PostPaidServerNic().withSubnetId("{your subnet id}"); List<PostPaidServerNic> list = new LinkedList<>(); list.add(nic); // 系统盘信息 PostPaidServerRootVolume root = new PostPaidServerRootVolume().withVolumetype(PostPaidServerRootVolume.VolumetypeEnum.SATA); PostPaidServer servers = new PostPaidServer().withAvailabilityZone(az) .withFlavorRef(flavorRef) .withImageRef(imageRef) .withName(name) .withNics(list) .withRootVolume(root) .withVpcid(vpcId) .withCount(100) .withIsAutoRename(false); CreatePostPaidServersRequestBody body = new CreatePostPaidServersRequestBody().withServer(servers); CreatePostPaidServersRequest request = new CreatePostPaidServersRequest().withBody(body); CreatePostPaidServersResponse response = ecsClient.createPostPaidServers(request); System.out.println(response.toString()); }}3. 批量删除弹性云服务器Demo// Step1: 查询当前以"live-stream"为开头的虚拟机列表ListServersDetailsRequest listServersDetailsRequest = new ListServersDetailsRequest().withName("live-stream");ListServersDetailsResponse listServersDetailsResponse = ecsClient.listServersDetails(listServersDetailsRequest); // Step2: 构造删除请求中的ServerId列表List<ServerDetail> serversList = listServersDetailsResponse.getServers();List<ServerId> serverIdList = new ArrayList<>();for(ServerDetail server : serversList) { ServerId id = new ServerId().withId(server.getId()); serverIdList.add(id);} // Step3: 传入serverId列表,删除虚拟机DeleteServersRequestBody deleteServersRequestBody = new DeleteServersRequestBody().withServers(serverIdList);DeleteServersRequest deleteServersRequest = new DeleteServersRequest().withBody(deleteServersRequestBody);DeleteServersResponse deleteServersResponse = ecsClient.deleteServers(deleteServersRequest);活动取得了非常好的成绩,实现了短视频平台流量和用户增长的目标,但是这次老板居然没有表扬我,我还有些纳闷:难道老板已经习惯了我的优秀?过了几天,HR小姐姐递过来一张表让我签字,表上写着:“调薪申请表,调薪幅度30%”,老板已经签好了名字。 目前API Explorer平台(https://apiexplorer.developer.huaweicloud.com/apiexplorer/overview?utm_source=apiwz&utm_medium=read)已开放EI企业智能、计算、应用服务、网络、软件开发平台、视频等70+云服务,共上线2000+个API、6000+个错误码。在前期试运行期间,华为云API Explorer平台上的API接口也已被多家企业成功接入。点击查看详情:《API Explorer新功能上线:支持一键分享调用参数,从此定位接口问题只要一键转发就行了,现在试用还有码豆拿哦》华为云API Explorer平台在未来几个月会实现更多功能,比如支持SDK示例代码、CLI等特性,同时也会开放更多的云服务API接口,连接更多开发者实现创新、拓宽创新边界。【拓展阅读】【API进阶之路】因为不会创建云服务器,我被实习生摆了一道【API进阶之路】前浪的绝地反击与自我证明【API进阶之路】甩锅大会上,我是如何绝地求生的【API进阶之路】一个技术预案,让老板当场喊出了“奥利给”【API进阶之路】万万没想到,一个技术方案帮实习生追到了运营妹子!【API进阶之路】一个技术盲点,差点让整个项目翻车【API进阶之路】老板给我涨薪30%!如何通过SDK接口搞定千万级流量直播【API进阶之路】半天搞定百万条手机号归属地查询,竟影响了公司战略方向!【API进阶之路】无法想象!大龄码农的硬盘里有这么多宝藏【API进阶之路】高考要考口语?一场10w+刷屏活动是如何用多模态评测API做出来的【API进阶之路】帮公司省下20万调研费!如何巧用情感分析API实现用户偏好调研【API进阶之路】逆袭!用关键词抽取API搞定用户需求洞察【华为云API学习赛】为入门初学者量身定制的学习平台,以赛带学,学以致用。参赛、邀请都有丰富奖品,还有机会拿P40 5G手机~API入门学习赛·AI人脸识别l 报名地址l 奖项设置API入门学习赛·探险寻宝之旅l 报名地址l 奖项设置
-
什么时候能够实现IoT Device SDK支持Node.js???
-
为什么result是空的?我的请求路径应该没有问题啊?
-
手头有个地图SDK,使用LCM进行通信,想请教下,如何将其适配到MDC上?有相关的例程吗?谢谢
-
在引入SDK的时候总是报“Class 'Obs\ObsClient' not found in”的错误 不知道是哪里的问题 引入的代码:require '/v1/huaweiyun/vendor/autoload.php';这是我的目录结构:
-
你好, 我在对象存储服务iOS SDK put上传完成的Response中未找到ObjectUrl,请问是需要自己拼接吗?拼接规则是?
上滑加载中
推荐直播
-
华为云码道Agent集成与鸿蒙实战2026/08/11 周二 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;彭江敏-华为云鸿蒙端云一体化开发专家
本次直播带你解读华为云码道7月份产品新特性、新功能。更有专家演示码道Agent Space × 钉钉机器集成实战,从0到1打通消息通道;码道鸿蒙端云一体化实战,快速搭建员工签到系统。
回顾中 -
华为云开发者AI素养直播课·第三期2026/08/21 周五 16:00-18:00
林华鼎-华为云AI开发者运营负责人;念擎-华为云AI开发者运营案例开发专家
本期直播内容:AI六层能力首次详细解读 + 新一代华为云开发者空间亮相 + 校园案例直播带练
回顾中
热门标签