单元测试junit+mock

news2024/10/6 20:28:34

单元测试

是什么?

单元测试(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 {
	@BeforeClass
	public static void setup() {
		System.out.println("@BeforeClass");
	}

	@Before
	public void setupThis() {
		System.out.println("@Before");
	}

	@Test
	public void method() {
		System.out.println("测试");
	}

	@After
	public void tearThis() {
		System.out.println("@After");
	}

	@AfterClass
	public static void tear() {
		System.out.println("@AfterClass");
	}
}
public class Demo2 {

    @Test
    public void test1() {
        System.out.println("@Test");
    }

    @Ignore
    @Test
    public 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 {
   @Test
   public void testAssertNull() {
      String str = null;
      assertNull(str);
   }

   @Test
   public void testAssertNotNull() {
      String str = "hello Java!!";
      assertNotNull(str);
   }

   @Test
   public void testAssertEqualsLong() {
      long long1 = 2;
      long long2 = 2;
      assertEquals(long1, long2);
   }

   @Test
   public void testAssertTrue() {
      List<String> list = new ArrayList<>();
      assertTrue(list.isEmpty());
   }

   @Test
   public void testAssertFalse() {
      List<String> list = new ArrayList<>();
      list.add("hello");
      assertFalse(list.isEmpty());
   }

   @Test
   public void testAssertSame() {
      String str1 = "hello world!!";
      String str2 = "hello world!!";
      assertSame(str2, str1);
   }

   @Test
   public 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 {

	@Rule
	public 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 {

   @Test
   public void test2() {
      System.out.println("test2");
   }
   
   @Test
   public void test1() {
      System.out.println("test1");
   }
   
   @Test
   public 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 的公共静态方法,并在此方法中初始化所有需要测试的参数对。
	@Parameters
	public static Iterable<Integer[]> getTestParamters() {
		return Arrays.asList(new Integer[][]{{2, 1, 1}, {3, 2, 1}, {4, 3, 1}});
	}

	// (5)步骤五:编写测试方法,使用定义的变量作为参数进行测试。 
	@Test
	public 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。

	@Test
	void 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() 方法,可以校验某些操作发生的次数。

	@Test
	void 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() 代码示例

	@Test
	void 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) 方法一起使用。

	@Mock
	private Random random;

	@Test
	void 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 方法的对比

	@Test
    void 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 注解代码示例


	@Spy
	private Demo demo;

	@Test
	 void 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 {

    @Autowired
    private UserService userService;

    @Test
    public 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 {
	@Autowired
	private MockMvc mvc;

	@MockBean
	private UserService userService;

	@Before
	public void setUp() {
		//打桩
		Mockito.when(userService.getUser(1)).thenReturn(new User(1, "张三"));
	}

	@Test
	public 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 {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public 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 {

    @Autowired
    private UserRepository userRepository;

    @Test
    public 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 {
	@Autowired
	private UserService userService;

	@MockBean
	private UserRepository userRepository;

	@Test
	public 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());
	}

	@TestConfiguration
	public static class prepareOrderService {
		@Bean
		public 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 {
	@Autowired
	private UserService userService;

	@MockBean
	private UserRepository userRepository;

	@Test
	public 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());
	}

	@TestConfiguration
	public static class prepareOrderService {
		@Bean
		public UserService getGlobalExceptionMsgSendService() {
			return new UserService();
		}
	}

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/333488.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java中类是什么

类(class)是构造对象的模板或蓝图。 我们可以将类想象成制作小甜饼的模具&#xff0c;将对象想象为小甜饼。由类构造(construct)对象的过程称为创建类的实例(instance)。 正如前面所看到的&#xff0c;用Java 编写的所有代码都位于某个类里面。 标准 Java 库提供了几千个类&a…

【Axure教程】转盘抽奖原型模板

转盘抽奖是营销活动中很常用的一种方式&#xff0c;在线上我们也可以经常看到转盘抽奖的活动&#xff0c;所以今天作者就教大家在Axure中怎么制作一个转盘抽奖的原型模板。一、效果展示1、可以随机转动轮盘&#xff0c;轮盘停止时&#xff0c;指针对着的奖品高亮显示2、可以重复…

Qt + Clion + cmake 环境配置

本文不涉及QML&#xff0c;因为我没用过 用C写窗体&#xff0c;同时还有可视化UI界面&#xff0c;这不比控制台程序香吗&#xff1f;QAQ我大一写c大作业的时候要是知道这个东西&#xff0c;我绝对满分啊&#xff01;&#xff01;&#xff01;&#xff01; To&#xff1a; 新版…

Mysql—触发器

触发器 简介 触发器用于直接在某种操作后&#xff08;数据的增删改查等&#xff09;&#xff0c;通过事件执行设置触发器时的 sql 语句&#xff0c;具有原子性。 可通过 sql 语句直接编写&#xff0c;关键词&#xff1a;CREATE TRIGGER 触发器名称。 例如&#xff1a;在表 st…

String面试题

String面试题 总结的很好&#xff1a;https://blog.csdn.net/qq_45950109/article/details/116992408 String特点 1.被final关键字修饰&#xff0c;不能被继承。实现Serializable&#xff0c;表示支持序列化。实现Comparable&#xff0c;表示可以排序。 2.底层是char数组和…

2023上半年软考报名到弘博创新错不了

软考是全国计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试&#xff08;简称软考&#xff09;项目&#xff0c;是由国家人力资源和社会保障部、工业和信息化部共同组织的国家级考试&#xff0c;既属于国家职业资格考试&#xff0c;又是职称资格考试。 系统集成…

ChatGPT为什么这么火爆?这是一篇从入门到玩坏的教程

什么是ChatGPT ChatGPT是由OpenAI开发的一个人工智能聊天机器人程序&#xff0c;于2022年11月推出。该程序使用基于GPT-3.5架构的大型语言模型並通过强化学习进行训练。 ChatGPT可以做什么&#xff1f; 你能想到的&#xff0c;它基本上都能和你聊上两句&#xff0c;比如写一…

功率放大器的增益是什么意思

电子工程师在日常实验测试中经常会应用到功率放大器&#xff0c;在介绍功率放大器产品的时候经常会看到增益的参数指标。下面安泰电子就来为大家介绍功率放大器增益是什么意思。 一、功率放大器增益的定义&#xff1a; 功率放大器作为一种电子电路&#xff0c;可以通过获取外部…

TCP连接的状态详解以及故障排查(六)

TCP通信中服务器处理客户端意外断开 如果TCP连接被对方正常关闭&#xff0c;也就是说&#xff0c;对方是正确地调用了closesocket(s)或者shutdown(s)的话&#xff0c;那么上面的Recv或Send调用就能马上返回&#xff0c;并且报错。这是由于close socket(s)或者shutdown(s)有个正…

SQL盲注加速方法总结

sql盲注加速方法总结 盲注分为布尔盲注和时间盲注&#xff0c;一般为加快测试速度都用工具或者脚本跑。但有时还是很慢&#xff0c;这时就需要采取另外办法。在参考了一些资料后经过实验总结可行方案如下。1.二分法加速、2.与运算加速、3.二进制延时注入加速、4.dnslog OOB外带…

[Java 进阶面试题] HashTable, HashMap, ConcurrentHashMap 之间的区别

大家一切顺利~ 文章目录前言HashTable, HashMap, ConcurrentHashMap 之间的区别前言 本篇主要内容如标题 HashTable, HashMap, ConcurrentHashMap 之间的区别 1.ConcurrentHashMap最大优化之处是相比于HashTable,ConcurrentHashMap大大缩小了所冲突的范围,把一把大锁切成了多…

全球爆火的ChatGPT,能否推动芯片市场增长?

“我所热爱的是我真实的生活&#xff0c;因为它包含了我所有的经历和感受&#xff0c;是我每一天都在体验和思考的。”这句非常有诗意的话&#xff0c;来自最近爆火的ChatGPT。 ChatGPT作为一款智能机器人&#xff0c;上知天文下知地理&#xff0c;不仅能写文案&#xff0c;还…

在github上上传文件

一、new新建一个仓库 填写/勾选下面三个部分 二、右键本地的要上传的文件&#xff0c;选择”Git Bash Here"进入。 进入git界面&#xff1a; 三、依次输入下面的命令 1、生成readme文件。 echo "# 在这里填入readme里面的内容" >> README.md2、建立…

(深度学习快速入门)第五章第一节1:GAN概述

获取pdf&#xff1a;密码7281 一&#xff1a;什么是生成模型 生成模型&#xff1a;在概率统计理论中&#xff0c;生成模型是指能够随机生成观测数据的模型&#xff0c;尤其是在给定某些隐含参数的条件下。为了训练一个生成模型我们首先要收集在特定领域下的大量数据&#xff…

Java开发学习(四十八)----MyBatisPlus删除语句之逻辑删除

1、逻辑删除 接下来要讲解是删除中比较重要的一个操作&#xff0c;逻辑删除&#xff0c;先来分析下问题: 这是一个员工和其所签的合同表&#xff0c;关系是一个员工可以签多个合同&#xff0c;是一个一(员工)对多(合同)的表 员工ID为1的张业绩&#xff0c;总共签了三个合同&a…

蓝桥杯刷题022——发现环(拓扑排序、DFS/BFS)

2017国赛 题目描述 小明的实验室有 N 台电脑&#xff0c;编号1⋯N。原本这 N 台电脑之间有 N−1 条数据链接相连&#xff0c;恰好构成一个树形网络。在树形网络上&#xff0c;任意两台电脑之间有唯一的路径相连。 不过在最近一次维护网络时&#xff0c;管理员误操作使得某两台电…

centos7安装pdf2htmlEX

1 概述 需要把PDF 转成 html,使用的是 pdf2htmlEX 工具。 2 安装 2.1 安装基本工具和依赖库 yum install vim unzip wget git gcc* cmake poppler* libtool* glib* gio* freetype* pango* cairo* -y 2.2 安装fontforge 2.2.1 下载 wget https://github.com/coolwanglu/f…

koa2-JWT登录验证、上传图片、上传视频

文章目录什么是JWT?怎么使用&#xff1f;后端进行token处理&#xff0c;传递给前端Token的使用分成了两部分前端的处理处理token后端处理携带和不携带token的请求上传图片会持续更新上传视频会持续更新什么是JWT?怎么使用&#xff1f; JWT&#xff08;JSON Web Token&#x…

K_A12_001 基于STM32等单片机采集火光火焰传感参数串口与OLED0.96双显示

K_A12_001 基于STM32等单片机采集火光火焰传感参数串口与OLED0.96双显示一、资源说明二、基本参数参数引脚说明三、驱动说明IIC地址/采集通道选择/时序对应程序:四、部分代码说明1、接线引脚定义1.1、STC89C52RC火光火焰模块1.2、STM32F103C8T6火光火焰模块五、基础知识学习与相…

Revit中添加水平仰视平面图及水平剖面

一、 Revit中如何添加水平仰视平面图 在Revit平面视图中视角是俯视视角&#xff0c;但是在一些特殊的情况下&#xff0c;我们可能需要创建仰视视角的平面视图&#xff0c;例如我们需要向上看天花板的灯具布置的时候。 1.下面讲一下如何在添加仰视平面视图的方法。如图1在模型中…