单元测试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 {
    
    
	@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
Method Description
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();
		}
	}

}

猜你喜欢

转载自blog.csdn.net/Fire_Sky_Ho/article/details/128961245