目录

  • 单元测试
    • Junit
      • 简单例子
    • mockito
      • Mock 的限制
    • Powermock
      • maven 引入
      • 注解使用
      • 处理私有方法
      • mock构造函数
      • 结合Springboot一起使用
      • 各种runner是何时如何起作用的呢
        • 首先runner是干啥的?
    • Springboot单元测试
  • Jacoco 收集单元测试覆盖率
    • 原理
      • offline 模式
      • on-the-fly 模式
        • Jacoco与Powermock的兼容问题
    • 术语
    • MAVEN多模块
    • 测试报告

单元测试

Junit

JUnit是一个Java语言的单元测试框架。它由Kent Beck和Erich Gamma建立,逐渐成为源于Kent Beck的sUnit的xUnit家族中最为成功的一个。 JUnit有它自己的JUnit扩展生态圈。多数Java的开发环境都已经集成了JUnit作为单元测试的工具。

JUnit是由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架(regression testing framework)。Junit测试是程序员测试,即所谓白盒测试,因为程序员知道被测试的软件如何(How)完成功能和完成什么样(What)的功能。Junit是一套框架,继承TestCase类,就可以用Junit进行自动测试了。
maven 依赖包

<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>compile</scope>
</dependency>

简单例子

import org.junit.Test;public class BasicTest {@Test // 声明是一个test casepublic void testSome () {assert true; // 断言这次单元测试执行是否成功}
}

mockito

Mockito 是一种 Java Mock 框架,主要是用来做 Mock 测试,它可以模拟任何 Spring 管理的 Bean、模拟方法的返回值、模拟抛出异常等等,避免你为了测试一个方法,却要自行构建整个 bean 的依赖链。

像是以下这张图,类 A 需要调用类 B 和类 C,而类 B 和类 C 又需要调用其他类如 D、E、F 等,假设类 D 是一个外部服务,那就会很难测,因为你的返回结果会直接的受外部服务影响,导致你的单元测试可能今天会过、但明天就过不了了。

而当我们引入 mock 测试时,就可以创建一个假的对象,替换掉真实的 bean B 和 C,这样在调用B、C的方法时,实际上就会去调用这个假的 mock 对象的方法,而我们就可以自己设定这个 mock 对象的参数和期望结果,让我们可以专注在测试当前的类 A,而不会受到其他的外部服务影响,这样测试效率就能提高很多。

可以使用mockito进行一些sevice的预期返回,假如你某一个service调用的是另外的服务,由于网络问题或者数据不匹配问题,你想让这个服务返回预期的数据。这个时候就可以使用mockito进行预期返回值设置。

HelloMockitoTest

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
@SpringBootTest
@PowerMockIgnore("javax.management.*")
@ContextConfiguration(classes = TestBizServer.class)
public class HelloMockitoTest {@InjectMocksprivate HelloController helloController;@Mockprivate HelloService helloService;@Beforepublic void init () {}@Testpublic void test () {// HelloService helloService = Mockito.mock(HelloService.class);// HelloController helloController = Mockito.mock(HelloController.class);// Mockito.when(helloService.sayHi()).thenReturn("Hello 优雅...");// String result = helloService.sayHi();// 创建真实对象Mockito.spy(helloService);// Mockito.doReturn("xxxx").when(helloService.sayHi());Mockito.when(helloService.sayHi()).thenReturn("你好啊!");String result2 = helloController.testHello();// System.out.println(result);System.out.println(result2);assert result2.equals("你好啊!");}
}

HelloController

@RestController
@RequestMapping("/hello")
public class HelloController {@Autowired(required = false)HelloService helloService;@GetMapping("/test")public String testHello () {String hello = null;try {Thread.sleep(1000);hello = helloService.sayHi();} catch (InterruptedException e) {e.printStackTrace();}return hello != null ? hello : "error";}
}

HelloService

@Service
public class HelloService implements InitializingBean {@Autowiredprivate HelloDao helloDao;public String sayHi () {System.out.println("HI ...");return "hi";}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("我是动态注册的你,不是容器启动的时候注册的你");}public boolean deleteOne () {System.out.println("------------------------------");return helloDao.deleteOne();}
}

最终输出结果 “单元测试通过”

Mock 的限制

不能 Mock 静态方法
不能 Mock private 方法
不能 Mock final class

Powermock

如果想详细学习Powermock请参考我另一篇文章:
Springboot 如何使用Powermock做单元测试

powermockmockito都是做mock的框架,powermock在mockito的基础上扩展而来,支持mockito的操作(也支持别的mock框架比如easyMock)。因此在maven引入powermock的时候,需要引mockito的包。powermock和mockito版本上要配合着使用。powermock在mockito的基础上,扩展了对static class, final class,constructor,private method等的mock操作。慎用这些mock,因为在一个良好的设计里,static final private这些class和method是不需要被测试的,会被public方法调用,只要测试public就好。

maven 引入

<properties><powermock.version>2.0.2</powermock.version>
</properties>
<dependencies><dependency><groupId>org.powermock</groupId><artifactId>powermock-module-junit4</artifactId><version>${powermock.version}</version><scope>test</scope></dependency><dependency><groupId>org.powermock</groupId><artifactId>powermock-api-mockito</artifactId><version>${powermock.version}</version><scope>test</scope></dependency>
</dependencies>

和spring配合使用的时候,要特别注意版本的问题,如果测试起不来的话,先确认下powermock的版本和spring是否对应。

注解使用

@powermockIgnore,默认情况下,powermock试图使用自己的classLoader去loader所有的class,除里system class(java.lang等目录下的class),使用powermockIgnore声明的class,powermock也不会加载。

处理私有方法

powermock提供了几种方法来处理私有方法,私有变量,私有构造函数。

  • Use Whitebox.setInternalState(…) to set a non-public member of an instance or class.
  • Use Whitebox.getInternalState(…) to get a non-public member of an instance or class.
  • Use Whitebox.invokeMethod(…) to invoke a non-public method of an instance or class.
  • Use Whitebox.invokeConstructor(…) to create an instance of a class with a private constructor.

mock构造函数

whenNew(MyClass.class).withNoArguments().thenThrow(new IOException(“error message”));

@RunWith(PowerMockRunner.class)
@PrepareForTest(X.class)
public class XTest {@Testpublic void test() {PowerMockito.whenNew(MyClass.class).withNoArguments().thenThrow(new IOException("error message"));X x = new X();x.y(); // y is the method doing "new MyClass()"..}
}
  • prepare的时候,prepareForTest的类是调用MyClass的类。

结合Springboot一起使用

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
@PrepareForTest(Test.class)
  • powerMock还是由自己的runner来做object的mock工作,在执行时,再交给delegate的runner去执行。
  • 不同的runner结合使用https://codete.com/blog/testing-spring-boot-application-with-junit-and-different-runners/

BlockJUnit4ClassRunner

@Override
protected void runChild(final FrameworkMethod method, RunNotifier notifier) {Description description = describeChild(method);if (method.getAnnotation(Ignore.class) != null) {notifier.fireTestIgnored(description);} else {runLeaf(methodBlock(method), description, notifier);}
}@Override
protected Description describeChild(FrameworkMethod method) {return Description.createTestDescription(getTestClass().getJavaClass(),testName(method), method.getAnnotations());
}@Override
protected List<FrameworkMethod> getChildren() {return computeTestMethods();
}

主要是这三个方法,getChildren得到所有@Test注解的方法。runChild中,将要调用的方法组织好,最后通过反射调用这个方法执行,同时处理执行成功或者执行失败的结果。

mockito的runner,JUnit44RunnerImpl,在跑test之前,将@Mock注解的对象构造出来。

SpringJUnit4ClassRunner 在test class中做依赖注入。

总之,就是各个不同的runner在处理各自框架的职责。mockitorunner的就是负责mock,spring的runner就是负责依赖注入。

这里也就解释了powermock的delegate是如何work的: testClass首先会交给powermockRunner完成自己的mock的工作,然后再交给springRunner去完成依赖注入的工作。

Understanding JUnit’s Runner architecture - DZone Java

Testing Spring Boot application with JUnit and different Runners | Codete blog

powermock 和 Jacoco的on-the-fly模式不兼容,如果想使用powermock只能使用jacoco的offline模式。

各种runner是何时如何起作用的呢

首先runner是干啥的?

runner其实就是各个框架在跑测试case的前后处理一些逻辑。
比如在Junit框架中,我们什么都不写,用Junit默认的Runner BlockJUnit4ClassRunner来执行case,主要做什么事情呢?就是处理Junit框架中的一些注解,比如扫到那些所有@Test的注解,这些是要跑的case,将那些@Ignore的注解的case忽略掉,在执行test case的前后,执行那些@Before@after的注解的方法。

Springboot单元测试

@RunWith(SpringRunner.class)
@SpringBootTest(classes = ServerInitializer.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class JunitTest {@MockBeanTestService testService;@Autowiredprotected MockMvc mockMvc;@Testpublic void Test1 () {Mockito.when(testService.testRequest(Mockito.anyString())).thenReturn("some");Assert.assertTrue(true);}@Testpublic void test2 () throws Exception {Mockito.when(testService.testRequest(Mockito.anyString())).thenReturn("这是mock返回的数据");MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/test").contentType(MediaType.APPLICATION_JSON_UTF8).param("xxx", "xxx")).andExpect(MockMvcResultMatchers.status().isOk()).andReturn();Result<String> map = JSON.parseObject(result.getResponse().getContentAsByteArray(), Result.class);Assert.assertNotNull(map);Assert.assertTrue("失败了,因为字符串不相等", map.getData().equals("HELLO STRANGER!"));
//         .andDo(MockMvcResultHandlers.print());}
}

伪造Session 写法:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = ServerInitializer.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class SpringMockSession {@MockBeanTestService testService;protected MockMvc mockMvc;@AutowiredWebApplicationContext webApplicationContext;// 伪造session@Beforepublic void before () {mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();MockHttpSession mockHttpSession = new MockHttpSession();// AuthUser authUser = new AuthUser();// mockHttpSession.setAttribute(USER_KEY, authUser);}@Testpublic void test2 () throws Exception {Mockito.when(testService.testRequest(Mockito.anyString())).thenReturn("这是mock返回的数据");MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/test").contentType(MediaType.APPLICATION_JSON_UTF8).param("xxx", "xxx")).andExpect(MockMvcResultMatchers.status().isOk()).andReturn();Result<String> map = JSON.parseObject(result.getResponse().getContentAsByteArray(), Result.class);Assert.assertNotNull(map);Assert.assertTrue("失败了,因为字符串不相等", map.getData().equals("HELLO STRANGER!"));
//         .andDo(MockMvcResultHandlers.print());}
}

Jacoco 收集单元测试覆盖率

Jacoco 是 Java 领域目前比较主流的覆盖率统计工具,它的统计过程可以分为打桩、测试用例执行、覆盖率统计和覆盖率数据解析并生成报告。

(1)首先对需要统计覆盖率的 Java 代码进行插桩,植入覆盖率统计代码,有 On-The-Fly 和 Offline 两种方式。
(2)执行测试用例,通过用例运行收集执行轨迹信息,保存在内存中。
(3)JVM 退出前将覆盖率数据保存至磁盘(二进制)或通过网络传送出去 。
(4)解析覆盖率文件,将代码覆盖率报告图形化展示出来,如 html、xml 等文件格式。

原理

根据插入字节码的时机不同,可以将覆盖率工具的运行方式分为offline与on-the-fly两种:

offline 模式

offline 模式会对编译后的字节码文件进行插桩并覆盖源文件,在启动 JVM 时直接加载插桩后的字节码。


offline 模式会对编译后字节码源文件进行修改,所以对用户的影响最大,但是对性能的影响最小。

  • 优点是不需要运行环境支持 java agent,不会与其他 agent 冲突。
  • 但需要添加 jacoco 编译字节码的 runtime 依赖。

on-the-fly 模式

在 JVM 加载类文件时,回调 javaagent 对字节码进行动态增强,植入覆盖率统计代码。

on-the-fly 模式会在应用启动时对加载进JVM的字节码文件进行插桩,不会改变用户的运行流程,只需要在JVM启动时配置 -javaagent 参数,更加无感。

  • 优点是直接添加启动参数即可快速进行覆盖率统计和分析。
  • 缺点是使用 javaagent 会降低一些启动速度以及 agent 冲突问题。

JaCoCo 提供了 maven 插件方便开发在项目中集成,提供了以下基本 goals,常用的包括 prepare-agent、report、instrument 和 restore-instrumented-classes。jacoco-maven-plugin 的 goals 与 Maven 生命周期的绑定关系如下:

validate
initialize .................. (prepare-agent 默认所属周期,注入 javaagent 参数)
generate-sources
process-sources
generate-resources
process-resources
compile
process-classes ............. (instrument 默认所属周期,offline 模式下对字节码插桩)
generate-test-sources
process-test-sources
generate-test-resources
process-test-resources
test-compile
process-test-classes
test ........................ (mvn test 执行的截止周期)
prepare-package ............. (restore-instrumented-classes 默认所属周期,offline 模式下恢复原始字节码)
package
pre-integration-test
integration-test
post-integration-test
verify ...................... (report 和 check 默认所属周期,report 用于生成覆盖率报告)
install
deploy

在默认的绑定关系中,当我们执行 mvn test 的时候,restore-instrumented-classes 和 report 默认不会被运行,因此为方便 offline 模式使用,我们需要修改下插件绑定的执行 phase,保证我们运行 mvn test 时可以正常运行,生成覆盖率报告。下面是两种不同模式的配置方案。

  • offline 模式Maven配置
<!-- surefire -->
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.16</version><dependencies><dependency><groupId>org.apache.maven.surefire</groupId><artifactId>surefire-junit4</artifactId><version>2.16</version></dependency></dependencies><configuration><systemPropertyVariables><jacoco-agent.destfile>${project.build.directory}/coverage.exec</jacoco-agent.destfile></systemPropertyVariables></configuration>
</plugin><!-- jacoco 插件配置 -->
<plugin><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artifactId><version>0.8.6</version><executions><execution><id>default-instrument</id><goals><goal>instrument</goal></goals></execution><execution><id>report</id><goals><goal>report</goal></goals><configuration><dataFile>${project.build.directory}/coverage.exec</dataFile></configuration></execution><execution><phase>test</phase><id>default-restore-instrumented-classes</id><goals><goal>restore-instrumented-classes</goal></goals></execution></executions>
</plugin><!-- 参考配置
<plugin><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artifactId><version>0.8.7</version><configuration><append>true</append></configuration><executions><execution><id>default-instrument</id><goals><goal>instrument</goal></goals></execution><execution><id>default-restore-instrumented-classes</id><goals><goal>restore-instrumented-classes</goal></goals></execution><execution><id>report</id><phase>prepare-package</phase><goals><goal>report</goal></goals><configuration><dataFile>target/jacoco.exec</dataFile><outputDirectory>target/jacoco-report</outputDirectory> # 报告输出路径</configuration></execution></executions>
</plugin>
-->
  • on-the-fly

aone 的默认测试插件默认采用这种模式。

<plugin><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artifactId><version>0.8.6</version><executions><execution><goals><goal>prepare-agent</goal></goals></execution><execution><id>report</id><phase>prepare-package</phase><goals><goal>report</goal></goals></execution></executions>
</plugin>

为什么要改默认的 phase?
  当我们使用 offline 模式运行 mvn test,如果按照默认的绑定关系,可能会遇到。
  Cannot process instrumented class 某个类名. Please supply original non-instrumented classes。
  原因是JaCoCo 的 instrumentprocess-classes 阶段将编译好的代码打桩用于统计代码覆盖率,然后需要在 restore-instrumented-classes 恢复原始字节码。
  但是执行 mvn test 时只到 test,而 restore-instrumented-classes 绑定在 prepare-package 阶段,因此 mvn test 默认不会触发 restore-instrumented-classes ,第二次 mvn test 时会重复打桩,引起报错。
  如果不改默认的 phase,则需要将 mvn test 改为 mvn verify 使用。verify 会运行 intergration-test 和 package 阶段,这两个阶段针对单元测试来说,不是十分必要。
  目前 Aone 代码覆盖率主要基于 JaCoCo 的 on-the-fly 模式进行代码覆盖率采集,通过自定义测试构建过程,利用 CI 插件自动注入 jacoco-maven-plugin,无需用户自己添加。配置过程可以参考下文。
  Aone 的各类测试任务底层复用了同一套执行引擎,类似 Maven 的 phase 和 goals,在 aone 中称为阶段和插件,每个阶段可以添加多个插件,例如下图在单元测试阶段,添加了代码 checkout 插件、codeconverage-unittest-pre(自动在 pom 文件中植入 JaCoCo 的 on-the-fly 配置)、单测和覆盖率解析插件。

The JaCoCo agent accepts the following options:

Jacoco与Powermock的兼容问题


官方文档讲Powermock和jacoco的on-the-fly模式并不兼容,只能与jacoco的offline模式兼容。而且如果是offline模式的话应该是无法多module汇总单元测试报告的。如果使用maven多module + on-the-fly模式是无法使用jacoco的。至少我这边测试是这样。

术语

行覆盖率:度量被测程序的每行代码是否被执行,判断标准行中是否至少有一个指令被执行。
类覆盖率:度量计算class类文件是否被执行。
分支覆盖率:度量if和switch语句的分支覆盖情况,计算一个方法里面的总分支数,确定执行和不执行的 分支数量。
方法覆盖率:度量被测程序的方法执行情况,是否执行取决于方法中是否有至少一个指令被执行。
指令覆盖:计数单元是单个java二进制代码指令,指令覆盖率提供了代码是否被执行的信息,度量完全 独立源码格式。
圈复杂度:在(线性)组合中,计算在一个方法里面所有可能路径的最小数目,缺失的复杂度同样表示测 试案例没有完全覆盖到这个模块。

MAVEN多模块

一般的SpringBoot项目会由多Module组成,每个Module为不同的功能模块。项目启动时,多个Module提供不同的服务,共同支持了本项目所提供的服务。若采用启动SpringBoot的方式进行多Module集成测试,一般test case会放在SpringApplication类所在的Module中,该Module一般仅提供了服务的入口,并无太多实际业务功能「简单来说,业务代码都不在这个Module中」。本文探讨运行集成测试,对多Module测试覆盖率合并统计的方法。

项目结构:

- pom.xml
|- subModule 1
|- - pom.xml
|- subModule 2
|- - pom.xml

Root pom.xml管理项目公共Maven配置,subModule 1为应用入口,SpringApplication类也在其中,SpringBoot也在此Module中启动;subModule 2为业务功能模块,提供Service服务。

使用JaCoCo生成测试覆盖率文档
由于官方只是强调实现了该功能,并未给出最佳实践,再次通过搜索资料,发现了这篇 StackOverflow 回复给出了最佳实践,按其中的指示操作即可:

在根 pom.xml 中添加 jacoco-maven-plugin:

<?xml version="1.0" encoding="UTF-8"?>
<project><dependencyManagement><dependencies><dependency><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artifactId><version>0.8.4</version></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artifactId><version>0.8.4</version><executions><execution><id>prepare-agent</id><goals><goal>prepare-agent</goal></goals></execution></executions></plugin></plugins></build>
</project>

在启动SpringBoot的子Module中,添加如下构建配置即可,不要忘了使用maven-surefire-plugin插件对test case进行管理。

<project><dependencies><dependency><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId></plugin><plugin><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artifactId><version>0.8.4</version><executions><execution><id>report-aggregate</id><phase>verify</phase><goals><goal>report-aggregate</goal></goals></execution></executions></plugin></plugins></build>
</project>

配置好后,只需要在应用根目录下「Root pom.xml所在的目录下」,执行Maven指令 mvn verify,之后在SpringBoot子Module中,打开target/site/jacoco-aggregate/index.html,即可在浏览器中查看详细的测试覆盖率报告了。

测试报告

参考文章:
单元测试框架和覆盖率统计原理简析(三)
powerMock和mockito使用
Multi Module Spring Boot集成测试使用JaCoCo生成测试覆盖率
Springboot 单元测试之Mock
JAVA代码覆盖率工具JaCoCo-原理篇

Springboot 单元测试结合Jacoco收集单元测试覆盖率相关推荐

  1. SpringBoot对单元测试支持、常用单元测试功能使用实例

    SpringBoot 单元测试 Spring Boot 提供了许多注解和工具帮助开发人员测试应用,在其官方文档中也用了大量篇幅介绍单元测试的使用.在谷歌每周的 TGIF (ThanksGod, it' ...

  2. SpringBoot结合Jacoco计算api覆盖率

    这里我主要准备三点内容: SpringBoot发布jar包 命令行运行SpingBoot.jar 通过ant dump Api代码覆盖率 开发环境 Win10 x64 jdk 1.8.0 ant 1. ...

  3. jacoco收集探针结果时机_滴滴开源Super-jacoco:java代码覆盖率收集平台

    Super-Jacoco是基于Jacoco.git二次开发打造的一站式JAVA代码全量/diff覆盖率收集平台,能够低成本.无侵入的收集代码覆盖率数据:Super-Jacoco除了支持JVM运行时间段 ...

  4. android单元测试作用,关于 Android 单元测试

    本文不会用各种高大上的理由试图去说服你写单元测试,只是描述笔者在单元测试这条路上一路走来的思考和简单的示例,如果顺便能让你觉得单元测试其实也没那么遥远.回头也在实际项目中尝试一下,估计就是本文最大的收 ...

  5. java 单元测试 私有成员变量,单元测试时测试一个private私有方法 - - ITeye博客

    直接上例子 待测试的类 [code="java"]public class Calculator { private int count = 0; private int add( ...

  6. 什么是单元测试?如何做好单元测试?

    在正式开始今天的话题之前,我先给你分享一个工厂生产电视机的例子. 工厂首先会将各种电子元器件按照图纸组装在一起构成各个功能电路板,比如供电板.音视频解码板.射频接收板等,然后再将这些电路板组装起来构成 ...

  7. c语言 单元测试工具 免费下载,雨田单元测试系统(C语言单元测试) 1.0官方版

    雨田单元测试系统(C语言单元测试)是一款适用于C语言文件的单元测试和集成测试系统.可以大幅度提高对C语言测试效率,从而提供软件质量. 雨田单元测试系统介绍 雨田单元测试系统可以针对c语言程序文件进行单 ...

  8. python单元测试示范卷_Python单元测试--Unittest

    原标题:Python单元测试--Unittest 什么是单元测试 单元测试是用来对最小可测试单元(如一个函数.一个类或者一个模块)进行检查和验证.尤其是在对代码进行修改或重构后,可以快速准确的定位出现 ...

  9. vcs 覆盖率收集2——覆盖率选项 + 合并覆盖率

    文章目录 前言 一.覆盖率 1.覆盖率选项 二.覆盖率查看 1.dve查看 2.verdi查看 3.urg查看 三.合并覆盖率urg 前言 2023.3.20 继续学习跑回归测试,以及查看覆盖率 一. ...

最新文章

  1. 前百度主任架构师创业,两年融资千万美元,他说AI新药研发将迎来黄金十年...
  2. jsp是在html中添加什么作用域,JSP九个内置对象 四大作用域 动作指令
  3. IIS 6和IIS 7 中设置文件上传大小限制设置方法,两者是不一样的
  4. c++中c_str()函数
  5. 【划分树】 POJ 2104 HDU 2665 K-th Number 裸题
  6. atitit. groupby linq的实现(1)-----linq框架选型 java .net php
  7. Linux 下安装matlab2014a
  8. Log4j使用详解(log4j.XML格式)
  9. LeetCode 381. O(1) 时间插入、删除和获取随机元素 - 允许重复(vector + 哈希)
  10. java的程序编码_Java 程序编码规范(初学者要牢记)
  11. python制作一个简易计算器_最简易的python计算器实现源代码
  12. w10计算机用户名密码忘了,一招简单帮你解决win10系统电脑忘记开机密码
  13. 百度收录批量查询_如何查看网站是否被收录?
  14. s8 android z,三星Galaxy S8领衔:2017年十佳Android智能手机
  15. python 虚拟串口通信
  16. 天涯明月刀电视剧全集(1-40)
  17. Practical Pigment Mixing for Digital Painting文献简单翻译
  18. C语言 详解如何编写闪烁显示字符串的函数
  19. 互联网摸鱼日报(2022-12-22)
  20. 仿ios桌面vivo_vivo仿ios主题教程 vivo设置ios主题的方法

热门文章

  1. 华为启动“备胎”计划,硅谷芯片企业受影响吗?
  2. el_table expand扩展单元格,自定义扩展样式
  3. Android实现奇怪的大冒险游戏菜单切换界面
  4. iOS怎么制作PDF图片和网络抓取图片
  5. 干货 | 揭开对机器学习的七点误解
  6. emeditor python_EmEditor
  7. 微信小程序:wxml中增加wxs脚本实现手机号/身份证等隐私信息显示
  8. HOOPS/MVO技术概述
  9. win10网络 计算机终止,又一个win10即将终止?各大版本终止日期大全,你准备好了吗...
  10. web前端学会使用图片轮播