当前位置: 首页 > news >正文

单元测试junit+mock

单元测试

是什么?

单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。至于“单元”的大小或范围,并没有一个明确的标准,“单元”可以是一个方法、类、功能模块或者子系统。
单元测试通常和白盒测试联系到一起,如果单从概念上来讲两者是有区别的,不过我们通常所说的“单元测试”和“白盒测试”都认为是和代码有关系的,所以在某些语境下也通常认为这两者是同一个东西。还有一种理解方式,单元测试和白盒测试就是对开发人员所编写的代码进行测试

作用

1.帮助理解需求
单元测试应该反映使用案例,把被测单元当成黑盒测试其外部行为。
2. 提高实现质量
单元测试不保证程序做正确的事,但能帮助保证程序正确地做事,从而提高实现质量。
3.测试成本低
相比集成测试、验收测试,单元测试所依赖的外部环境少,自动化程度高,时间短,节约了测试成本。
4.反馈速度快
单元测试提供快速反馈,把bug消灭在开发阶段,减少问题流到集成测试、验收测试和用户,降低了软件质量控制的成本。
5.利于重构
由于有单元测试作为回归测试用例,有助于预防在重构过程中引入bug。
6.文档作用
单元测试提供了被测单元的使用场景,起到了使用文档的作用。
7.对设计的反馈
一个模块很难进行单元测试通常是不良设计的信号,单元测试可以反过来指导设计出高内聚、低耦合的模块。

什么时候写单元测试?

更多的时候是同时在实现代码和单元测试。因为这样既可以在实现的过程中随时执⾏单元测试来验证,同时也避免分开写时要重复理解⼀遍设计需求,⼤⼤提⾼了效率,节约了时间。

这⾥特别要强调的⼀点是,有时候,写单元测试和不写单元测试,会直接影响到代码的设计和实现。⽐如要写⼀个有很多条件分⽀处理的函数,如果不考虑单测,你很可能把这所有的逻辑写在⼀个函数⾥。但是如果考虑到单测实现的简洁,你就会把各个分⽀各写成⼀个函数,然后把分⽀逻辑另写成⼀个函数,最终意外达到了优化代码的⽬的。所以评判代码或者设计好不好的⼀个准则是看它容不容易测试。

什么时候可以不写单元测试?

在个⼈的⼯作实践中,很少遇到可以不写单元测试的情况,当然确实有过不⽤写的时候。下面是可能遇到的几种情况,请自行掂量。

  • 函数逻辑太复杂了,历史上也从没有⼈为它写过单测,代码的reviewer也没有要求我写。

  • 代码的重要性不够,都是自己写自己维护的,即使代码有问题也不会有什么重要影响的。有些接⼝的⼤函数,典型如Main函数…

  • 写对应的单元测试⾮常的复杂,甚⾄⽆法写。这时候很可能

    • 需要修改设计,必须让你的设计易于单元测试
    • 需要增强单元测试框架,框架功能不够,不能很好⽀持某种场景下的单测。
    • 实在想不起来还有什么情况…也许有些涉及到⽤户交互的UI单元?

单元测试编写规范

  1. 好的单元测试必须遵守AIR原则。A:Automatic(自动化),I:Independent(独立性),R:Repeatable(可重复)

  2. Automatic(自动化) 单元测试应该是全自动执行的,并且非交互式的。测试用例通常是被定期执行的,执行过程必须完全自动化才有意义。输出结果需要人工检查的测试不是一个好的单元测试。单元测试中不准使用System.out来进行人肉认证,必须使用assert来验证。

  3. Independent(独立性) 保持单元测试的独立性。为了保证单元测试稳定可靠且便于维护,单元测试用例之间绝不能互相调用,也不能依赖执行的先后次序。

  4. Repeatable(可重复) 单元测试是可以重复执行的,不能受到外界环境的影响。单元测试通常会被放到持续集成中,每次有代码check in时单元测试都会被执行。如果单测对外部环境有依赖,容易导致持续继承机制的不可用。

  5. 对于单元测试,要保证测试粒度足够小,有助于精确定位问题,单测粒度至多是类级别,一般是方法级别。

  6. 核心业务、核心应用、核心模块的增量代码确保单元测试通过。

  7. 单元测试代码必须写在如下工程目录:src/test/java,不允许写在业务代码目录下。

  8. 每个单元测试应该有个好名字,让⼈⼀看就知道是做什么测试,如果名字不能说明问题也要加上完整的注释。⽐如 testSortNumbers_withDuplicated, 意味SortNumbers函数的单元测试来验证有重复数字的情况。

代码覆盖率

是什么?

代码覆盖率是对整个测试过程中被执行的代码的衡量,它能测量源代码中的哪些语句在测试中被执行,哪些语句尚未被执行。

为什么要测量代码覆盖率?

众所周知,测试可以提高软件版本的质量和可预测性。但是,你知道你的单元测试甚至是你的功能测试实际测试代码的效果如何吗?是否还需要更多的测试?

这些是代码覆盖率可以试图回答的问题。总之,出于以下原因我们需要测量代码覆盖率:

  • 了解我们的测试用例对源代码的测试效果
  • 了解我们是否进行了足够的测试
  • 在软件的整个生命周期内保持测试质量

注:代码覆盖率不是灵丹妙药,覆盖率测量不能替代良好的代码审查和优秀的编程实践。

通常,我们应该采用合理的覆盖目标,力求在代码覆盖率在所有模块中实现均匀覆盖,而不是只看最终数字的是否高到令人满意。

举例:假设代码覆盖率只在某一些模块代码覆盖率很高,但在一些关键模块并没有足够的测试用例覆盖,那样虽然代码覆盖率很高,但并不能说明产品质量就很高。

代码覆盖率的指标种类

代码覆盖率工具通常使用一个或多个标准来确定你的代码在被自动化测试后是否得到了执行,常见的覆盖率报告中看到的指标包括:

  • 函数覆盖率:定义的函数中有多少被调用
  • 语句覆盖率:程序中的语句有多少被执行
  • 分支覆盖率:针对 if…else、case 等分支语句,看代码中设计的分支是否都被测试到了。针对 if(条件1),只要条件 1 取 true 和 false 都执行过,则这个分支就完全覆盖了。
  • 条件覆盖率:条件覆盖率可以看作是对分支覆盖率的补充。每一个分支条件表达式中,所有条件的覆盖。
  • 行覆盖率:有多少行的源代码被测试过

对比main方法优点

比代码中写main 方法测试的好处:

  1. 可以书写一系列的 测试方法,对项目所有的 接口或者方法进行单元测试。
  2. 启动后,自动化测试,并判断执行结果, 不需要人为的干预
  3. 只需要查看最后结果,就知道整个项目的方法接口是否通畅。。
  4. 每个单元测试用例相对独立, 由Junit 启动,自动调用。 不需要添加额外的调用语句。

而main 方法不一样。
对多个方法调用。 需要添加打印或者输出语句。
添加了新的测试方法。 需要在main方法添加方法调用。
不能形成整体的测试结果。
需要对打印或者输出结果进行人为的判断。

JUnit

JUnit 是一个 Java 编程语言的单元测试框架。JUnit 在测试驱动的开发方面有很重要的发展,是起源于 JUnit 的一个统称为 xUnit 的单元测试框架之一。

注解

JUnit 提供以下注解来编写测试。

注解描述
@RunWith用于设置测试运行器。例如,我们可以通过 @RunWith(SpringJUnit4ClassRunner.class) 让测试运行于 Spring 测试环境。
@Before带注解的方法将在测试类中的每个测试方法之前运行。
@After带注解的方法将在测试类中的每个测试方法之后运行。
@BeforeClass带注解的方法将在测试类中的所有测试方法之前运行。 此方法必须是静态的。
@AfterClass带注解的方法将在测试类中的所有测试方法之后运行。 此方法必须是静态的。
@Test用于将方法标记为 junit 测试
@Ignore它用于禁用或忽略测试套件中的测试类或方法。
@Rule引用规则,在一个class中所有的@Test标注过的测试方法都会共享这个Rule

一个单元测试类执行顺序为:

@BeforeClass> @Before> @Test> @After> `@AfterClass

每一个测试方法的调用顺序为:

@Before> @Test> @After

编写测试

在 JUnit 中,测试方法带有@Test注解。 为了运行该方法,JUnit 首先构造一个新的类实例,然后调用带注解的方法。 测试抛出的任何异常将由 JUnit 报告为失败。 如果未引发任何异常,则假定测试成功。

public class Demo1 {@BeforeClasspublic static void setup() {System.out.println("@BeforeClass");}@Beforepublic void setupThis() {System.out.println("@Before");}@Testpublic void method() {System.out.println("测试");}@Afterpublic void tearThis() {System.out.println("@After");}@AfterClasspublic static void tear() {System.out.println("@AfterClass");}
}
public class Demo2 {@Testpublic void test1() {System.out.println("@Test");}@Ignore@Testpublic void testIgnore() {System.out.println("@Ignore");}
}

断言方法

**断言(assertion)**是一种在程序中的一阶逻辑(如:一个结果为真或假的逻辑判断式),目的为了表示与验证软件开发者预期的结果——当程序执行到断言的位置时,对应的断言应该为真。若断言不为真时,程序会中止执行,并给出错误信息。

Junit 4 Assert Methods
MethodDescription
assertNull(java.lang.Object object)检查对象是否为空
assertNotNull(java.lang.Object object)检查对象是否不为空
assertEquals(long expected, long actual)检查long类型的值是否相等
assertFalse(boolean condition)检查条件是否为假
assertTrue(boolean condition)检查条件是否为真
assertNotSame(java.lang.Object unexpected, java.lang.Object actual)

检查两个对象引用是否不引用统一对象(即对象不等)

案例:

public class Demo3 {@Testpublic void testAssertNull() {String str = null;assertNull(str);}@Testpublic void testAssertNotNull() {String str = "hello Java!!";assertNotNull(str);}@Testpublic void testAssertEqualsLong() {long long1 = 2;long long2 = 2;assertEquals(long1, long2);}@Testpublic void testAssertTrue() {List<String> list = new ArrayList<>();assertTrue(list.isEmpty());}@Testpublic void testAssertFalse() {List<String> list = new ArrayList<>();list.add("hello");assertFalse(list.isEmpty());}@Testpublic void testAssertSame() {String str1 = "hello world!!";String str2 = "hello world!!";assertSame(str2, str1);}@Testpublic void testAssertNotSame() {String str1 = "hello world!!";String str3 = "hello Java!!";assertNotSame(str1, str3);}
}

期望异常测试

有两种方法实现:

1. @Test(expected…)

@Test注解有一个可选的参数,"expected"允许你设置一个Throwable的子类

2. ExpectedException

如果要使用JUnit框架中的ExpectedException类,需要声明ExpectedException异常。

案例:

public class Demo4 {@Rulepublic ExpectedException thrown = ExpectedException.none();public void division() {int i = 5 / 0;}@Test(expected = ArithmeticException.class)public void test1() {division();}@Test()public void test2() {thrown.expect(ArithmeticException.class);division();}}

优先级测试

将测试方法构成测试回环的时候,就需要确定测试方法执行顺序,以此记录。

@FixMethodOrder是控制@Test方法执行顺序的注解,她有三种选择

MethodSorters.JVM 按照JVM得到的顺序执行
MethodSorters.NAME_ASCENDING 按照方法名字顺序执行
MethodSorters.DEFAULT 按照默认顺序执行 以确定的但是不可预期的顺序执行(hashcode大小)

@(MethodSorters.JVM)
public class Demo5 {@Testpublic void test2() {System.out.println("test2");}@Testpublic void test1() {System.out.println("test1");}@Testpublic void test3() {System.out.println("test3");}}

参数化测试

参数化测试主要解决一次性进行多个测试用例的测试。其主要思想是,将多个测试用例按照,{输入值,输出值}(输入值可以是多个)的列表方式进行测试。

//(1)步骤一:测试类指定特殊的运行器org.junit.runners.Parameterized
@RunWith(Parameterized.class)
public class Demo6 {// (2)步骤二:为测试类声明变量,分别用于存放期望值和测试所用数据。private final int expected;private final int a;private final int b;public Demo6(int expected, int a, int b) {this.expected = expected;this.a = a;this.b = b;}// (4)步骤四:为测试类声明一个使用注解 org.junit.runners.Parameterized.Parameters 修饰的,// 返回值为java.lang.Iterable 的公共静态方法,并在此方法中初始化所有需要测试的参数对。@Parameterspublic static Iterable<Integer[]> getTestParamters() {return Arrays.asList(new Integer[][]{{2, 1, 1}, {3, 2, 1}, {4, 3, 1}});}// (5)步骤五:编写测试方法,使用定义的变量作为参数进行测试。 @Testpublic void testAdd() {Demo calculator = new Demo();System.out.println("输入参数 " + a + " and " + b + ",预期值 " + expected);assertEquals(expected, calculator.add(a, b));}
}

超时测试

如果一个测试用例比起指定的毫秒数花费了更多的时间,那么 Junit 将自动将它标记为失败。timeout 参数和 @Test注释一起使用。现在让我们看看活动中的 @test(timeout)。

public class Demo7 {@Test(timeout = 1000)public void testTimeout() throws InterruptedException {TimeUnit.SECONDS.sleep(2);System.out.println("Complete");}
}

上面测试会失败,在一秒后会抛出异常 org.junit.runners.model.TestTimedOutException: test timed out after 1000 milliseconds

Mock

为什么要使用 mock

  • Mock 的意思是模拟,它可以用来对系统、组件或类进行隔离。

    在测试过程中,我们通常关注测试对象本身的功能和行为,而对测试对象涉及的一些依赖,仅仅关注它们与测试对象之间的交互(比如是否调用、何时调用、调用的参数、调用的次数和顺序,以及返回的结果或发生的异常等),并不关注这些被依赖对象如何执行这次调用的具体细节。

    因此,Mock 机制就是使用 Mock 对象替代真实的依赖对象,并模拟真实场景来开展测试工作。

    使用 Mock 对象完成依赖关系测试的示意图如下所示:

    SpringBoot 应用程序测试实现方案

    可以看出,在形式上,Mock 是在测试代码中直接 Mock 类和定义 Mock 方法的行为,通常测试代码和 Mock 代码放一起。因此,测试代码的逻辑从测试用例的代码上能很容易地体现出来。

Mockito 中常用方法

Mockito的使用,一般有以下几种组合:

  • do/when:包括doThrow(…).when(…)/doReturn(…).when(…)/doAnswer(…).when(…) ,返回值为void时使用
  • given/will:包括given(…).willReturn(…)/given(…).willAnswer(…)
  • when/then: 包括when(…).thenReturn(…)/when(…).thenAnswer(…)

Mock 方法

mock 方法来自 org.mockito.Mock,它表示可以 mock 一个对象或者是接口。

public static <T> T mock(Class<T> classToMock)
  • classToMock:待 mock 对象的 class 类。
  • 返回 mock 出来的类

实例:使用 mock 方法 mock 一个类

Random random = Mockito.mock(Random.class);

对 Mock 出来的对象进行行为验证和结果断言

验证是校验待验证的对象是否发生过某些行为,Mockito 中验证的方法是:verify。

	@Testvoid addTest() {Random random = Mockito.mock(Random.class);System.out.println(random.nextInt());Mockito.verify(random).nextInt();// Mockito.verify(random, Mockito.times(2)).nextInt();}

使用 verify 验证:

Verify 配合 time() 方法,可以校验某些操作发生的次数。

	@Testvoid addTest() {Random random = Mockito.mock(Random.class);System.out.println(random.nextInt());Mockito.verify(random, Mockito.times(2)).nextInt();}

断言使用到的类是 Assert.

Random random = Mockito.mock(Random.class, "test");
Assert.assertEquals(100, random.nextInt());

输出结果:

org.opentest4j.AssertionFailedError: 
Expected :100
Actual   :0

当使用 mock 对象时,如果不对其行为进行定义,则 mock 对象方法的返回值为返回类型的默认值。

给 Mock 对象打桩

桩,或称桩代码,是指用来代替关联代码或者未实现代码的代码。如果函数B用B1来代替,那么,B称为原函数,B1称为桩函数。打桩就是编写或生成桩代码。

打桩可以理解为 mock 对象规定一行的行为,使其按照我们的要求来执行具体的操作。在 Mockito 中,常用的打桩方法为

方法含义
when().thenReturn()Mock 对象在触发指定行为后返回指定值
when().thenThrow()Mock 对象在触发指定行为后抛出指定异常
when().doCallRealMethod()Mock 对象在触发指定行为后调用真实的方法

thenReturn() 代码示例

	@Testvoid addTestOngoingStubbing() {MockitoAnnotations.initMocks(this);Mockito.when(random.nextInt()).thenReturn(1); //打桩,指定返回值System.out.println(random.nextInt());}
输出1

Mockito 中常用注解

可以代替 Mock 方法的 @Mock 注解

Shorthand for mocks creation - @Mock annotation

Important! This needs to be somewhere in the base class or a test runner:

快速 mock 的方法,使用 @mock 注解。

mock 注解需要搭配 MockitoAnnotations.initMocks(testClass) 方法一起使用。

	@Mockprivate Random random;@Testvoid addTestAnnotations() {//开启注解,否则空指针MockitoAnnotations.initMocks(this);System.out.println(random.nextInt());Mockito.verify(random).nextInt();}

Spy 方法与 @Spy 注解

spy() 方法与 mock() 方法不同的是

  1. 被 spy 的对象会走真实的方法,而 mock 对象不会
  2. spy() 方法的参数是对象实例,mock 的参数是 class

示例:spy 方法与 Mock 方法的对比

	@Testvoid addTestMockAndSpyDifferent() {Demo mock = Mockito.mock(Demo.class);Assert.assertEquals(0, mock.add(1, 2));Demo spy = Mockito.spy(new Demo());Assert.assertEquals(3, spy.add(1, 2));}

输出结果

// 第一个 Assert 断言失败,因为没有给 Demo 对象打桩,因此返回默认值
java.lang.AssertionError: expected:<3> but was:<0>
预期:3
实际:0

使用 @Spy 注解代码示例

@Spyprivate Demo demo;@Testvoid addTestAnnotations() {MockitoAnnotations.initMocks(this);int res = demo.add(1, 2);Assert.assertEquals(3, res);// Assert.assertEquals(4,res);}

Spring Boot 中使用 JUnit

Spring 框架提供了一个专门的测试模块(spring-test),用于应用程序的集成测试。 在 Spring Boot 中,你可以通过spring-boot-starter-test启动器快速开启和使用它。

Spring Boot 测试

// 获取启动类,加载配置,确定装载 Spring 程序的装载方法,它回去寻找 主配置启动类(被 @SpringBootApplication 注解的)
@SpringBootTest
// 让 JUnit 运行 Spring 的测试环境, 获得 Spring 环境的上下文的支持
@RunWith(SpringRunner.class)
public class Demo1 {@Autowiredprivate UserService userService;@Testpublic void getUser() {User user = userService.getUser(1);Assert.assertEquals("bob",user.getName());}
}

@SpringBootTest - webEnvironment

  • MOCK:加载 WebApplicationContext 并提供一个 Mock 的 Servlet 环境,此时内置的 Servlet 容器并没有正式启动。
  • RANDOM_PORT:加载 EmbeddedWebApplicationContext 并提供一个真实的 Servlet 环境,然后使用一个随机端口启动内置容器。
  • DEFINED_PORT:这个配置也是通过加载 EmbeddedWebApplicationContext 提供一个真实的 Servlet 环境,但使用的是默认端口,如果没有配置端口就使用 8080。
  • NONE:加载 ApplicationContext 但并不提供任何真实的 Servlet 环境。

在 Spring Boot 中,@SpringBootTest 注解主要用于测试基于自动配置的 ApplicationContext,它允许我们设置测试上下文中的 Servlet 环境。

在多数场景下,一个真实的 Servlet 环境对于测试而言过于重量级,通过 MOCK 环境则可以缓解这种环境约束所带来的困扰

@RunWith 注解与 SpringRunner

在上面的示例中,我们还看到一个由 JUnit 框架提供的 @RunWith 注解,它用于设置测试运行器。例如,我们可以通过 @RunWith(SpringJUnit4ClassRunner.class) 让测试运行于 Spring 测试环境。

虽然这我们指定的是 SpringRunner.class,实际上,**SpringRunner 就是 SpringJUnit4ClassRunner 的简化,它允许 JUnit 和 Spring TestContext 整合运行,而 Spring TestContext 则提供了用于测试 Spring 应用程序的各项通用的支持功能。

Spring MVC 测试

当你想对 Spring MVC 控制器编写单元测试代码时,可以使用@WebMvcTest注解。它提供了自配置的 MockMvc,可以不需要完整启动 HTTP 服务器就可以快速测试 MVC 控制器。

使用@WebMvcTest注解时,只有一部分的 Bean 能够被扫描得到,它们分别是:

  • @Controller
  • @ControllerAdvice
  • @JsonComponent
  • Filter,WebMvcConfigurer,HandlerMethodArgumentResolver
  • 其他常规的@Component(包括@Service、@Repository等)Bean 则不会被加载到 Spring 测试环境上下文中。

注意:

  • 如果报错:java.lang.IllegalStateException: Found multiple @SpringBootConfiguration annotated classes...... ,在类上添加注解@ContextConfiguration(classes = {测试启动类.class}),加载配置类
@RunWith(SpringRunner.class)
@WebMvcTest(UserController.class)
@Slf4j
public class Demo2 {@Autowiredprivate MockMvc mvc;@MockBeanprivate UserService userService;@Beforepublic void setUp() {//打桩Mockito.when(userService.getUser(1)).thenReturn(new User(1, "张三"));}@Testpublic void getUser() throws Exception {MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.get("/user/1"))//构建请求, 测试的相对地址.andExpect(status().isOk()) // 期待返回状态吗码200.andExpect(jsonPath("$.name").value(IsEqual.equalTo("张三"))) // 这里是期待返回值是 张三.andDo(print())//打印输出流.andReturn();//返回结果String content = mvcResult.getResponse().getContentAsString(Charset.defaultCharset());log.info("返回结果:{}", content);}
}

Spring Boot Web 测试

当你想启动一个完整的 HTTP 服务器对 Spring Boot 的 Web 应用编写测试代码时,可以使用@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)注解开启一个随机的可用端口。Spring Boot 针对 REST 调用的测试提供了一个 TestRestTemplate 模板,它可以解析链接服务器的相对地址。

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Slf4j
public class Demo3 {@Autowiredprivate TestRestTemplate restTemplate;@Testpublic void getUser(){ResponseEntity<User> result = restTemplate.getForEntity("/user/2", User.class);User body = result.getBody();Assert.assertThat(body, Matchers.notNullValue());log.info("User:{}", body);}
}

使用 @DataJpaTest 注解测试数据访问组件

如要需要使用真实环境中的数据库进行测试,需要替换掉默认规则,使用@AutoConfigureTestDatabase(replace = Replace.NONE)注解:

@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class Demo4 {@Autowiredprivate UserRepository userRepository;@Testpublic void getUser(){User user = userRepository.findById(2).orElse(null);assert user != null;Assert.assertThat("tom", Matchers.is(user.getName()));}
}

Spring Service层测试

@RunWith(SpringRunner.class)
public class Demo6 {@Autowiredprivate UserService userService;@MockBeanprivate UserRepository userRepository;@Testpublic void testGetUser() {User user1 = new User(1, "zs");Mockito.when(userRepository.findById(1)).thenReturn(Optional.of(user1));User user2 = userService.getUser(1);Assert.assertEquals(user1.getId(), user2.getId());}@TestConfigurationpublic static class prepareOrderService {@Beanpublic UserService getGlobalExceptionMsgSendService() {return new UserService();}}}

rElse(null);
assert user != null;
Assert.assertThat(“tom”, Matchers.is(user.getName()));
}
}


## Spring Service层测试```java
@RunWith(SpringRunner.class)
public class Demo6 {@Autowiredprivate UserService userService;@MockBeanprivate UserRepository userRepository;@Testpublic void testGetUser() {User user1 = new User(1, "zs");Mockito.when(userRepository.findById(1)).thenReturn(Optional.of(user1));User user2 = userService.getUser(1);Assert.assertEquals(user1.getId(), user2.getId());}@TestConfigurationpublic static class prepareOrderService {@Beanpublic UserService getGlobalExceptionMsgSendService() {return new UserService();}}}

相关文章:

单元测试junit+mock

单元测试 是什么&#xff1f; 单元测试&#xff08;unit testing&#xff09;&#xff0c;是指对软件中的最小可测试单元进行检查和验证。至于“单元”的大小或范围&#xff0c;并没有一个明确的标准&#xff0c;“单元”可以是一个方法、类、功能模块或者子系统。 单元测试通…...

2022Q4手机银行新版本聚焦提升客群专属、财富开放平台、智能化能力,活跃用户规模6.91亿人

易观&#xff1a;2022年第4季度&#xff0c;手机银行APP迭代升级加快&#xff0c;手机银行作为零售银行服务及经营的主阵地&#xff0c;与零售银行业务发展的联系日益紧密。迭代升级一方面可以顺应零售银行发展战略及方向&#xff0c;对手机银行业务布局进行针对性调整优化&…...

YOLO-V1~V3经典物体检测算法介绍

大名鼎鼎的YOLO物体检测算法如今已经出现了V8版本&#xff0c;我们先来了解一下它前几代版本都做了什么吧。本篇文章介绍v1-v3&#xff0c;后续会继续更新。一、节深度学习经典检测方法概述1.1 检测任务中阶段的意义我们所学的深度学习经典检测方法 &#xff0c;有些是单阶段的…...

SparkSQL 核心编程

文章目录SparkSQL 核心编程1、新的起点2、SQL 语法1) 读取 json 文件创建 DataFrame2) 对 DataFrame 创建一个临时表3) 通过SQL语句实现查询全表3、DSL 语法1) 创建一个DataFrame2) 查看DataFrame的Schema信息3) 只查看"username"列数据4) 查看"username"列…...

Android核心开发【UI绘制流程解析+原理】

一、UI如何进行具体绘制 UI从数据加载到具体展现的过程&#xff1a; 进程间的启动协作&#xff1a; 二、如何加载到数据 应用从启动到onCreate的过程&#xff1a; Activity生产过程详解&#xff1a; 核心对象 绘制流程源码路径 1、Activity加载ViewRootImpl ActivityThread…...

计算机组成原理第七章笔记记录

仅仅作为笔记记录,B站视频链接&#xff0c;若有错误请指出&#xff0c;谢谢 基本概念 演变过程 I/O系统基本组成 I/O软件 包括驱动程序、用户程序、管理程序、升级补丁等 下面的两种方式是用来实现CPU和I/O设备的信息交换的 I/O指令 CPU指令的一部分,由操作码,命令码,设备…...

ORB-SLAM2编译、安装等问题汇总大全(Ubuntu20.04、eigen3、pangolin0.5、opencv3.4.10)

ORB-SLAM2编译、安装等问题汇总大全&#xff08;Ubuntu20.04、eigen3、pangolin0.5、opencv3.4.10&#xff09; 1&#xff1a;环境说明: 使用的Linux发行版本为Ubuntu 20.04 SLAM2下载地址为&#xff1a;git clone https://github.com/raulmur/ORB_SLAM2.git ORB_SLAM2 2&a…...

QuickBuck:一款专为安全研究人员设计的勒索软件模拟器

关于QuickBuck QuickBuck是一款基于Golang开发的勒索软件模拟工具&#xff0c;在该工具的帮助下&#xff0c;广大研究人员可以通过更简单的方法来判断反病毒保护方案是否能够有效地预防勒索软件的攻击。 功能介绍 该工具能够模拟下列勒索软件典型行为&#xff0c;其中包括&a…...

【八大数据排序法】堆积树排序法的图形理解和案例实现 | C++

第二十一章 堆积树排序法 目录 第二十一章 堆积树排序法 ●前言 ●认识排序 1.简要介绍 2.图形理解 3.算法分析 ●二、案例实现 1.案例一 ● 总结 前言 排序算法是我们在程序设计中经常见到和使用的一种算法&#xff0c;它主要是将一堆不规则的数据按照递增…...

低代码开发平台|生产管理-生产加工搭建指南

1、简介1.1、案例简介本文将介绍&#xff0c;如何搭建生产管理-生产加工。1.2、应用场景在主生产计划列表中下达加工后&#xff0c;在加工单列表可操作领料、质检。2、设置方法2.1、表单搭建1&#xff09;新建表单【产品结构清单&#xff08;BOM&#xff09;】&#xff0c;字段…...

Python类型-语句-函数

文章目录类型动态类型:变量类型会随着程序的运行发生改变注释控制台控制台输入input()运算符算术关系逻辑赋值总结语句判断语句while循环for循环函数链式调用和嵌套调用递归关键字传参在C/java中&#xff0c;整数除以整数结果还是整数&#xff0c;并不会将小数部分舍弃&#xf…...

真兰仪表在创业板开启申购:募资约20亿元,IPO市值约为78亿元

2月9日&#xff0c;上海真兰仪表科技股份有限公司&#xff08;下称“真兰仪表”&#xff0c;SZ:301303&#xff09;开启申购&#xff0c;将在深圳证券交易所创业板上市。本次上市&#xff0c;真兰仪表的发行价为26.80元/股&#xff0c;市盈率43.06倍。 据贝多财经了解&#xf…...

【2023】Prometheus-Prometheus与Alertmanager配置详解

记录一下Prometheus与Alertmanager的配置参数等内容 目录1.Prometheus1.1.prometheus.yml1.2.告警规则定义2.alertmanager2.1.alertmanager.yml2.1.1.global&#xff1a;全局配置2.1.1.1.以email方式作为告警发送方2.1.1.2.以wechat方式作为告警发送方2.1.1.3.以webhook方式作为…...

华为HCIE学习之openstack基础

文章目录一、Openstack各种文件位置二、Openstack命令操作1.使用帮助三、用命令发放云主机1、创建租户2、创建用户并与租户绑定3、注册镜像4、创建规格5、创建公有网络及其子网&#xff08;做弹性IP用&#xff09;6、创建私有网络及其子网7、创建路由并设置网关与端口8、创建安…...

Python实现贝叶斯优化器(Bayes_opt)优化BP神经网络分类模型(BP神经网络分类算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。1.项目背景贝叶斯优化器(BayesianOptimization) 是一种黑盒子优化器&#xff0c;用来寻找最优参数。贝叶斯优化器是基…...

Elasticsearch(九)搜索---搜索辅助功能(下)--搜索性能分析

一、前言 上篇文章我们学习了ES的搜索辅助功能的一部分–分别是指定搜索返回的字段&#xff0c;搜索结果计数&#xff0c;分页&#xff0c;那么本次我们来学习一下ES的性能分析相关功能。 二、ES性能分析 在使用ES的过程中&#xff0c;有的搜索请求的响应比较慢&#xff0c;…...

化繁为简|中信建投基于StarRocks构建统一查询服务平台

近年来&#xff0c;在证券服务逐渐互联网化&#xff0c;以及券商牌照红利逐渐消退的行业背景下&#xff0c;中信建投不断加大对数字化的投入&#xff0c;尤其重视数据基础设施的建设&#xff0c;期望在客户服务、经营管理等多方面由经验依赖向数据驱动转变&#xff0c;从而提高…...

2023数字中国创新大赛·数据开发赛道首批赛题启动报名

由数字中国建设峰会组委会主办的2023数字中国创新大赛&#xff08;DCIC 2023&#xff09;已正式启幕&#xff0c;本届大赛结合当下数字技术发展的热点和业界关注的焦点&#xff0c;面向产业实际需求设置了九大赛道。其中&#xff0c;数据开发赛道2月8日正式上线首批赛题&#x…...

MySQL数据库

1.MySQL的MyISAM与InnoDB两种存储引擎在&#xff0c;事务、锁级别&#xff0c;各自的适用场景? 1.1事务处理上方面 MyISAM&#xff1a;强调的是性能&#xff0c;每次查询具有原子性,其执行数度比InnoDB类型更快&#xff0c;但是不提供事务支持。 InnoDB&#xff1a;提供事务…...

鸿蒙设备学习|快速上手BearPi-HM Micro开发板

系列文章目录 第一章 鸿蒙设备学习|初识BearPi-HM Micro开发板 第二章 鸿蒙设备学习|快速上手BearPi-HM Micro开发板 文章目录系列文章目录前言一、环境要求1.硬件要求2.软件要求3.Linux构建工具要求4.Windows开发工具要求5.工具下载地址二、安装编译基础环境1.安装Linux编译环…...

软件测试标准流程

软件测试的基本流程大概要经历四个阶段&#xff0c;分别是制定测试计划、测试需求分析、测试用例设计与编写以及测试用例评审。因此软件测试的工作内容&#xff0c;远远没有许多人想象的只是找出bug那么简单。准确的说&#xff0c;从一个项目立项以后&#xff0c;软件测试从业者…...

Python身份运算符

Python身份运算符身份运算符用于比较两个对象的存储单元运算符描述实例isis 是判断两个标识符是不是引用自一个对象x is y, 类似 id(x) id(y) , 如果引用的是同一个对象则返回 True&#xff0c;否则返回 Falseis notis not 是判断两个标识符是不是引用自不同对象x is not y &a…...

linux 安装,卸载jdk8

1>安装1 xshell,xsftp 教育版下载 https://www.xshell.com/zh/free-for-home-school/ 2下载jdk包 https://www.oracle.com/java/technologies/downloads/3在usr下新建java文件夹把jdk包拉进去解压tar -zxvf 4首先使用vim打开etc目录下的profile文件 --> vim /etc/profile…...

标准舆情监测平台解决方案及流程,TOOM舆情监测工作计划有哪些?

舆情监测流程一般包括&#xff1a;数据收集、数据分析、信息汇报三个部分。首先&#xff0c;通过多种途径收集舆情数据&#xff0c;如网络媒体、社交媒体、博客、论坛等;其次&#xff0c;对收集的数据进行分析&#xff0c;统计舆情趋势、舆情类型等;最后&#xff0c;根据舆情分…...

Lombok使用总结

文章目录介绍Lombok原理常用注解DataGetterSetterToStringEqualsAndHashCodeNoArgsConstructorAllArgsConstructorRequiredArgsConstructorAccessors(chain true)遇到的问题谨慎使用Data问题总结Builder和Data不能共用解决介绍 官网&#xff1a;https://projectlombok.org/ …...

Qt 如何处理耗时的线程,不影响主线程响应 QApplication::processEvents)

事件原因&#xff1a; 前些时间遇到一个问题&#xff0c;在主线程接收子线程读的数据&#xff0c;一直接收不到&#xff0c;但放在子线程没有问题&#xff1b; 后面查了一下&#xff0c;因为接收子线程使用了 qApp->processEvents(); 查了一下 qApp->processEvents(); …...

Antd-table全选踩坑记录

目录 一、需求 二、问题 ​编辑三、解决 四、全选选中所有数据而不是当前页 一、需求 最近遇到一个小小的需求&#xff0c;在我们这个项目中&#xff0c;有一个表格需要添加全选删除功能。这还不简单吗&#xff0c;于是我找到andt的官网&#xff0c;咔咔咔一顿cv&#xff0…...

防灾必看,边滑坡安全预警解决方案

一、行业背景在我国大部分地区经常会有雨季发生&#xff0c;大量的雨水渗透到了土壤内部&#xff0c;长时间饱含雨水的土壤会变得很重而且还会减少与下方岩石之间的摩擦力&#xff0c;顺着山坡这个滑梯滑下去&#xff0c;造成崩塌、滑坡、泥石流等地质灾害。地质灾害每年都是有…...

你每天所做的工作,让你产生了成就感吗?

我们是为了什么而工作&#xff1f;金钱&#xff1f;理想&#xff1f;生活&#xff1f; 似乎这一切都没有标准答案&#xff0c;你自己问你自己&#xff0c;问问你自己&#xff0c;每天踏入公司&#xff0c;坐到工位面前&#xff0c;你最真实的感受是什么&#xff1f; “成就感…...

MySQL中的锁

共享锁 共享锁也成为读锁&#xff0c;针对同一份数据&#xff0c;多个事务的读操作可以同时进行而不会互相影响&#xff0c;相互不阻塞的。 通过下面命令加共享锁 SELECT...LOCK IN SHARE MODE #或 SELECT...FOR SHARE;#(8.0新增语法)排他锁 排他锁也叫写锁&#xff0c;当一…...