【单元测试】单元测试之Mockito的使用

目录

  • 一、前期准备
    • 1、准备工作
    • 2、入门知识
    • 3、五分钟入门Demo
  • 二、让我们开始学习吧!
    • 1、行为验证
    • 2、如何做一些测试桩stub
    • 3、参数匹配器
    • 4、执行顺序验证
    • 5、确保交互(interaction)操作不会执行在mock对象上
    • 6、使用注解简化mock对象创建
    • 7、监控真实对象(部分mock)
    • 8、@Mock 和 @Spy的使用
    • 9、ArgumentCaptor(参数捕获器)捕获方法参数进行验证。(可代替参数匹配器使用)
    • 10、简化 ArgumentCaptor 的创建
    • 11、高级特性:自定义验证失败信息
    • 12、高级特性:修改没有测试桩的调用的默认返回值
  • 三、学习了这么多,牛刀小试一下!

一、前期准备

1、准备工作

<!--mockito依赖-->
<dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><version>2.7.19</version><scope>test</scope>
</dependency>
<!-- junit依赖 -->
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope>
</dependency>

2、入门知识

1)Mockito:简单轻量级的做mocking测试的框架;

2)mock对象:在调试期间用来作为真实对象的替代品;

3)mock测试:在测试过程中,对那些不容易构建的对象用一个虚拟对象来代替测试的方法就叫mock测试;

4)stub:打桩,就是为mock对象的方法指定返回值(可抛出异常);

5)verify:行为验证,验证指定方法调用情况(是否被调用,调用次数等);

3、五分钟入门Demo

@Test
public void test0() {//1、创建mock对象(模拟依赖的对象)final List mock = Mockito.mock(List.class);//2、使用mock对象(mock对象会对接口或类的方法给出默认实现)System.out.println("mock.add result => " + mock.add("first"));  //falseSystem.out.println("mock.size result => " + mock.size());       //0//3、打桩操作(状态测试:设置该对象指定方法被调用时的返回值)Mockito.when(mock.get(0)).thenReturn("second");Mockito.doReturn(66).when(mock).size();//3、使用mock对象的stub(测试打桩结果)System.out.println("mock.get result => " + mock.get(0));    //secondSystem.out.println("mock.size result => " + mock.size());   //66//4、验证交互 verification(行为测试:验证方法调用情况)Mockito.verify(mock).get(Mockito.anyInt());Mockito.verify(mock, Mockito.times(2)).size();//5、验证返回的结果(这是JUnit的功能)assertEquals("second", mock.get(0));assertEquals(66, mock.size());
}

二、让我们开始学习吧!

1、行为验证

一旦mock对象被创建了,mock对象会记住所有的交互,然后你就可以选择性的验证你感兴趣的交互,验证不通过则抛出异常。

@Test
public void test1() {final List mockList = Mockito.mock(List.class);mockList.add("mock1");mockList.get(0);mockList.size();mockList.clear();// 验证方法被使用(默认1次)Mockito.verify(mockList).add("mock1");// 验证方法被使用1次Mockito.verify(mockList, Mockito.times(1)).get(0);// 验证方法至少被使用1次Mockito.verify(mockList, Mockito.atLeast(1)).size();// 验证方法没有被使用Mockito.verify(mockList, Mockito.never()).contains("mock2");// 验证方法至多被使用5次Mockito.verify(mockList, Mockito.atMost(5)).clear();// 指定方法调用超时时间Mockito.verify(mockList, timeout(100)).get(0);// 指定时间内需要完成的次数Mockito.verify(mockList, timeout(200).atLeastOnce()).size();
}

2、如何做一些测试桩stub

默认情况下,所有的函数都有返回值。mock函数默认返回的是null,一个空的集合或者一个被对象类型包装的内置类型,例如0、false对应的对象类型为Integer、Boolean;

一旦测试桩函数被调用,该函数将会一致返回固定的值;

对于 static 和 final 方法, Mockito 无法对其 when(…).thenReturn(…) 操作。

@Test
public void test2() {//静态导入,减少代码量:import static org.mockito.Mockito.*;final ArrayList mockList = mock(ArrayList.class);// 设置方法调用返回值when(mockList.add("test2")).thenReturn(true);doReturn(true).when(mockList).add("test2");System.out.println(mockList.add("test2"));  //true// 设置方法调用抛出异常when(mockList.get(0)).thenThrow(new RuntimeException());doThrow(new RuntimeException()).when(mockList).get(0);System.out.println(mockList.get(0));    //throw RuntimeException// 无返回方法打桩doNothing().when(mockList).clear();// 为回调做测试桩(对方法返回进行拦截处理)final Answer<String> answer = new Answer<String>() {@Overridepublic String answer(InvocationOnMock invocationOnMock) throws Throwable {final List mock = (List) invocationOnMock.getMock();return "mock.size result => " + mock.size();}};when(mockList.get(1)).thenAnswer(answer);doAnswer(answer).when(mockList).get(1);System.out.println(mockList.get(1));    //mock.size result => 0// 对同一方法多次打桩,以最后一次为准when(mockList.get(2)).thenReturn("test2_1");when(mockList.get(2)).thenReturn("test2_2");System.out.println(mockList.get(2));    //test2_2System.out.println(mockList.get(2));    //test2_2// 设置多次调用同类型结果when(mockList.get(3)).thenReturn("test2_1", "test2_2");when(mockList.get(3)).thenReturn("test2_1").thenReturn("test2_2");System.out.println(mockList.get(3));    //test2_1System.out.println(mockList.get(3));    //test2_2// 为连续调用做测试桩(为同一个函数调用的不同的返回值或异常做测试桩)when(mockList.get(4)).thenReturn("test2").thenThrow(new RuntimeException());doReturn("test2").doThrow(new RuntimeException()).when(mockList).get(4);System.out.println(mockList.get(4));    //test2System.out.println(mockList.get(4));    //throw RuntimeException// 无打桩方法,返回默认值System.out.println(mockList.get(99));    //null
}

3、参数匹配器

参数匹配器使验证和测试桩变得更灵活;

为了合理的使用复杂的参数匹配,使用equals()与anyX() 的匹配器会使得测试代码更简洁、简单。有时,会迫使你重构代码以使用equals()匹配或者实现equals()函数来帮助你进行测试;

如果你使用参数匹配器,所有参数都必须由匹配器提供;

支持自定义参数匹配器;

@Testpublic void test3() {final Map mockMap = mock(Map.class);// 正常打桩测试when(mockMap.get("key")).thenReturn("value1");System.out.println(mockMap.get("key"));     //value1// 为灵活起见,可使用参数匹配器when(mockMap.get(anyString())).thenReturn("value2");System.out.println(mockMap.get(anyString()));   //value2System.out.println(mockMap.get("test_key"));    //value2System.out.println(mockMap.get(0)); //null// 多个入参时,要么都使用参数匹配器,要么都不使用,否则会异常when(mockMap.put(anyString(), anyInt())).thenReturn("value3");System.out.println(mockMap.put("key3", 3));     //value3System.out.println(mockMap.put(anyString(), anyInt()));     //value3System.out.println(mockMap.put("key3", anyInt()));    //异常// 行为验证时,也支持使用参数匹配器verify(mockMap, atLeastOnce()).get(anyString());verify(mockMap).put(anyString(), eq(3));}

4、执行顺序验证

验证执行顺序是非常灵活的-你不需要一个一个的验证所有交互,只需要验证你感兴趣的对象即可;

你可以仅通过那些需要验证顺序的mock对象来创建InOrder对象;

@Test
public void test4() {// 验证同一个对象多个方法的执行顺序final List mockList = mock(List.class);mockList.add("first");mockList.add("second");final InOrder inOrder = inOrder(mockList);inOrder.verify(mockList).add("first");inOrder.verify(mockList).add("second");// 验证多个对象多个方法的执行顺序final List mockList1 = mock(List.class);final List mockList2 = mock(List.class);mockList1.get(0);mockList1.get(1);mockList2.get(0);mockList1.get(2);mockList2.get(1);final InOrder inOrder1 = inOrder(mockList1, mockList2);inOrder1.verify(mockList1).get(0);inOrder1.verify(mockList1).get(2);inOrder1.verify(mockList2).get(1);
}

5、确保交互(interaction)操作不会执行在mock对象上

一些用户可能会在频繁地使用verifyNoMoreInteractions(),甚至在每个测试函数中都用。但是verifyNoMoreInteractions()并不建议在每个测试函数中都使用;

verifyNoMoreInteractions()在交互测试套件中只是一个便利的验证,它的作用是当你需要验证是否存在冗余调用时;

@Test
public void test5() {// 验证某个交互是否从未被执行final List mock = mock(List.class);mock.add("first");verify(mock, never()).add("test5");   //通过verify(mock, never()).add("first");  //异常// 验证mock对象没有交互过final List mock1 = mock(List.class);final List mock2 = mock(List.class);verifyZeroInteractions(mock1);  //通过verifyNoMoreInteractions(mock1, mock2); //通过verifyZeroInteractions(mock, mock2);  //异常// 注意:可能只想验证前面的逻辑,但是加上最后一行,会导致出现异常。建议使用方法层面的验证,如:never();//      在验证是否有冗余调用的时候,可使用此种方式。如下:final List mockList = mock(List.class);mockList.add("one");mockList.add("two");verify(mockList).add("one");    // 通过verify(mockList, never()).get(0);    //通过verifyZeroInteractions(mockList);   //异常
}

6、使用注解简化mock对象创建

注意!下面这句代码需要在运行测试函数之前被调用,一般放到测试类的基类或者test runner中:

MockitoAnnotations.initMocks(this);

也可以使用内置的runner: MockitoJUnitRunner 或者一个rule : MockitoRule;

// 代替 mock(ArgumentTestService.class) 创建mock对象;
@Mock
private ArgumentTestService argumentTestService;
// 若改注解修饰的对象有成员变量,@Mock定义的mock对象会被自动注入;
@InjectMocks
private MockitoAnnotationServiceImpl mockitoAnnotationService;@Test
public void test6() {// 注意!下面这句代码需要在运行测试函数之前被调用,一般放到测试类的基类或者test runner中;MockitoAnnotations.initMocks(this);when(argumentTestService.argumentTestMethod(new ArgumentTestRequest())).thenReturn("success");System.out.println(argumentTestService.argumentTestMethod(new ArgumentTestRequest()));  //successSystem.out.println(mockitoAnnotationService.mockitoAnnotationTestMethod()); //null
}

7、监控真实对象(部分mock)

可以为真实对象创建一个监控(spy)对象。当你使用这个spy对象时真实的对象也会也调用,除非它的函数被stub了;

尽量少使用spy对象,使用时也需要小心形式,例如spy对象可以用来处理遗留代码;

stub语法中同样提供了部分mock的方法,可以调用真实的方法;

完全mock:

上文讲的内容是完全mock,即创建的mock对象与真实对象无关,mock对象的方法默认都是基本的实现,返回基本类型。可基于接口、实现类创建mock对象。

部分mock:

所谓部分mock,即创建的mock对象时基于真实对象的,mock对象的方法都是默认使用真实对象的方法,除非stub之后,才会以stub为准。基于实现类创建mock对象,否则在没有stub的情况下,调用真实方法时,会出现异常。

注意点:

Mockito并不会为真实对象代理函数调用,实际上它会拷贝真实对象。因此如果你保留了真实对象并且与之交互,不要期望从监控对象得到正确的结果。 当你在监控对象上调用一个没有被stub的函数时并不会调用真实对象的对应函数,你不会在真实对象上看到任何效果

@Test
public void test7() {// stub部分mock(stub中使用真实调用)。注意:需要mock实现类,否则会有异常final StubTestService stubTestService = mock(StubTestServiceImpl.class);when(stubTestService.stubTestMethodA("paramA")).thenCallRealMethod();doCallRealMethod().when(stubTestService).stubTestMethodB();System.out.println(stubTestService.stubTestMethodA("paramA"));  //stubTestMethodA is called, param = paramASystem.out.println(stubTestService.stubTestMethodB());  //stubTestMethodB is calledSystem.out.println(stubTestService.stubTestMethodC());  //null// spy部分mockfinal LinkedList<String> linkedList = new LinkedList();final LinkedList spy = spy(linkedList);spy.add("one");spy.add("two");doReturn(100).when(spy).size();when(spy.get(0)).thenReturn("one_test");System.out.println(spy.size()); //100System.out.println(spy.get(0)); //one_testSystem.out.println(spy.get(1)); //two// spy可以类比AOP。在spy中,由于默认是调用真实方法,所以第二种写法不等价于第一种写法,不推荐这种写法。doReturn("two_test").when(spy).get(2);when(spy.get(2)).thenReturn("two_test"); //异常 java.lang.IndexOutOfBoundsException: Index: 2, Size: 2System.out.println(spy.get(2));   //two_test// spy对象只是真实对象的复制,真实对象的改变不会影响spy对象final List<String> arrayList = new ArrayList<>();final List<String> spy1 = spy(arrayList);spy1.add(0, "one");System.out.println(spy1.get(0));    //onearrayList.add(0, "list1");System.out.println(arrayList.get(0));   //list1System.out.println(spy1.get(0));    //one// 若对某个方法stub之后,又想调用真实的方法,可以使用reset(spy)final ArrayList<String> arrayList1 = new ArrayList<>();final ArrayList<String> spy2 = spy(arrayList1);doReturn(100).when(spy2).size();System.out.println(spy2.size());    //100reset(spy2);System.out.println(spy2.size());    //0
}

8、@Mock 和 @Spy的使用

@Mock 等价于 Mockito.mock(Object.class);

@Spy 等价于 Mockito.spy(obj);

区分是mock对象还是spy对象:
Mockito.mockingDetails(someObject).isMock();
Mockito.mockingDetails(someObject).isSpy();@Mock
private StubTestService stubTestService;
@Spy
private StubTestServiceImpl stubTestServiceImpl;
@Spy
private StubTestService stubTestServiceImpl1 = new StubTestServiceImpl();
@Test
public void test8() {MockitoAnnotations.initMocks(this);// mock对象返回默认System.out.println(stubTestService.stubTestMethodB());  //null// spy对象调用真实方法System.out.println(stubTestServiceImpl.stubTestMethodC());  //stubTestMethodC is calledSystem.out.println(stubTestServiceImpl1.stubTestMethodA("spy"));  //stubTestMethodA is called, param = spy// 区分是mock对象还是spy对象System.out.println(mockingDetails(stubTestService).isMock());   //trueSystem.out.println(mockingDetails(stubTestService).isSpy());    //falseSystem.out.println(mockingDetails(stubTestServiceImpl).isSpy());    //true
}

9、ArgumentCaptor(参数捕获器)捕获方法参数进行验证。(可代替参数匹配器使用)

在某些场景中,不光要对方法的返回值和调用进行验证,同时需要验证一系列交互后所传入方法的参数。那么我们可以用参数捕获器来捕获传入方法的参数进行验证,看它是否符合我们的要求。

ArgumentCaptor介绍

通过ArgumentCaptor对象的forClass(Class

ArgumentCaptor的Api

argument.capture() 捕获方法参数

argument.getValue() 获取方法参数值,如果方法进行了多次调用,它将返回最后一个参数值

argument.getAllValues() 方法进行多次调用后,返回多个参数值

@Test
public void test9() {List mock = mock(List.class);List mock1 = mock(List.class);mock.add("John");mock1.add("Brian");mock1.add("Jim");// 获取方法参数ArgumentCaptor argument = ArgumentCaptor.forClass(String.class);verify(mock).add(argument.capture());System.out.println(argument.getValue());    //John// 多次调用获取最后一次ArgumentCaptor argument1 = ArgumentCaptor.forClass(String.class);verify(mock1, times(2)).add(argument1.capture());System.out.println(argument1.getValue());    //Jim// 获取所有调用参数System.out.println(argument1.getAllValues());    //[Brian, Jim]
}

10、简化 ArgumentCaptor 的创建

@Mock
private List<String> captorList;
@Captor
private ArgumentCaptor<String> argumentCaptor;
@Test
public void test10() {MockitoAnnotations.initMocks(this);captorList.add("cap1");captorList.add("cap2");System.out.println(captorList.size());verify(captorList, atLeastOnce()).add(argumentCaptor.capture());System.out.println(argumentCaptor.getAllValues());
}

11、高级特性:自定义验证失败信息

@Test
public void test11() {final ArrayList arrayList = mock(ArrayList.class);arrayList.add("one");arrayList.add("two");verify(arrayList, description("size()没有调用")).size();// org.mockito.exceptions.base.MockitoAssertionError: size()没有调用verify(arrayList, timeout(200).times(3).description("验证失败")).add(anyString());//org.mockito.exceptions.base.MockitoAssertionError: 验证失败
}

12、高级特性:修改没有测试桩的调用的默认返回值

可以指定策略来创建mock对象的返回值。这是一个高级特性,通常来说,你不需要写这样的测试;

它对于遗留系统来说是很有用处的。当你不需要为函数调用打桩时你可以指定一个默认的answer;

@Test
public void test12(){// 创建mock对象、使用默认返回final ArrayList mockList = mock(ArrayList.class);System.out.println(mockList.get(0));    //null// 这个实现首先尝试全局配置,如果没有全局配置就会使用默认的回答,它返回0,空集合,null,等等。// 参考返回配置:ReturnsEmptyValuesmock(ArrayList.class, Answers.RETURNS_DEFAULTS);// ReturnsSmartNulls首先尝试返回普通值(0,空集合,空字符串,等等)然后它试图返回SmartNull。// 如果最终返回对象,那么会简单返回null。一般用在处理遗留代码。// 参考返回配置:ReturnsMoreEmptyValuesmock(ArrayList.class, Answers.RETURNS_SMART_NULLS);// 未stub的方法,会调用真实方法。//    注1:存根部分模拟使用时(mock.getSomething ()) .thenReturn (fakeValue)语法将调用的方法。对于部分模拟推荐使用doReturn语法。//    注2:如果模拟是序列化反序列化,那么这个Answer将无法理解泛型的元数据。mock(ArrayList.class, Answers.CALLS_REAL_METHODS);// 深度stub,用于嵌套对象的mock。参考:https://www.cnblogs.com/Ming8006/p/6297333.htmlmock(ArrayList.class, Answers.RETURNS_DEEP_STUBS);// ReturnsMocks首先尝试返回普通值(0,空集合,空字符串,等等)然后它试图返回mock。// 如果返回类型不能mocked(例如是final)然后返回null。mock(ArrayList.class, Answers.RETURNS_MOCKS);//  mock对象的方法调用后,可以返回自己(类似builder模式)mock(ArrayList.class, Answers.RETURNS_SELF);// 自定义返回final Answer<String> answer = new Answer<String>() {@Overridepublic String answer(InvocationOnMock invocation) throws Throwable {return "test_answer";}};final ArrayList mockList1 = mock(ArrayList.class, answer);System.out.println(mockList1.get(0));   //test_answer
}

三、学习了这么多,牛刀小试一下!

测试实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {/*** 姓名,登录密码*/private String name;private String password;
}

持久层DAO

public interface UserDao {/*** 根据name查找user* @param name* @return*/User getUserByName(String name);/*** 保存user* @param user* @return*/Integer saveUser(User user);
}

业务层Service接口

public interface UserService {/*** 根据name查找user* @param name* @return*/User getUserByName(String name);/*** 保存user* @param user* @return*/Integer saveUser(User user);
}

业务层Serive实现类

@Service
public class UserServiceImpl implements UserService {//userDao@Resourceprivate UserDao userDao;/*** 根据name查找user* @param name* @return*/@Overridepublic User getUserByName(String name) {try {return userDao.getUserByName(name);} catch (Exception e) {throw new RuntimeException("查询user异常");}}/*** 保存user* @param user* @return*/@Overridepublic Integer saveUser(User user) {if (userDao.getUserByName(user.getName()) != null) {throw new RuntimeException("用户名已存在");}try {return userDao.saveUser(user);} catch (Exception e) {throw new RuntimeException("保存用户异常");}}
}

现在我们的Service写好了,想要单元测试一下,但是Dao是其他人开发的,目前还没有写好,那我们如何测试呢?

public class UserServiceTest {/*** Mock测试:根据name查询user*/@Testpublic void getUserByNameTest() {// mock对象final UserDao userDao = mock(UserDao.class);final UserServiceImpl userService = new UserServiceImpl();
//        userService.setUserDao(userDao);// stub调用final User user = new User();user.setName("admin");user.setPassword("pass");when(userDao.getUserByName("admin")).thenReturn(user);// 执行待测试方法final User user1 = userService.getUserByName("admin");System.out.println("查询结果:" + JacksonUtil.obj2json(user1));  //查询结果:{"name":"admin","password":"pass"}// 验证mock对象交互verify(userDao).getUserByName(anyString());// 验证查询结果Assert.assertNotNull("查询结果为空!", user1);Assert.assertEquals("查询结果错误!", "admin", user1.getName());}/*** Mock测试:保存user*/@Mockprivate UserDao userDao;@InjectMocksprivate UserServiceImpl userService;@Testpublic void saveUserTest() throws Exception{// 执行注解初始化MockitoAnnotations.initMocks(this);// mock对象stub操作final User user = new User();user.setName("admin");user.setPassword("pass");when(userDao.getUserByName("admin")).thenReturn(user).thenReturn(null);when(userDao.saveUser(any(User.class))).thenReturn(1);// 验证用户名重复的情况try {userService.saveUser(user);throw new Exception();  //走到这里说明验证失败} catch (RuntimeException e) {System.out.println("重复用户名保存失败-测试通过");   //重复用户名保存失败-测试通过}verify(userDao).getUserByName("admin");// 验证正常保存的情况user.setName("user");final Integer integer = userService.saveUser(user);System.out.println("保存结果:" + integer);  //保存结果:1Assert.assertEquals("保存失败!", 1, integer.longValue());verify(userDao).saveUser(any(User.class));verify(userDao, times(2)).getUserByName(anyString());}
}

根据以上代码我们可以知道,当我们的待测类开发完成而依赖的类的实现还没有开发完成。此时,我们就可以用到我们的Mock测试,模拟我们依赖类的返回值,使我们的待测类与依赖类解耦。这样,我们就可以对我们的待测类进行单元测了。

Jnuit文章见《【单元测试】一文读懂java单元测试》

代码地址GitHub

觉得有用的话还请来个三连!!!

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

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

相关文章

【C语言基础】:字符串函数(二)

文章目录 一、strncpy函数的使用二、strncat函数的使用三、strncmp函数的使用四、strstr函数的使用和模拟实现4.1 strstr函数的使用4.2 strstr函数的模拟实现 五、strtok函数的使用六、strerror函数的使用 上节回顾&#xff1a;【C语言基础】&#xff1a;字符函数和字符串函数 …

软考高级:软件架构评估-质量属性-安全性概念和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

子矩阵(十四届蓝桥杯python组A)

这题思路就是用两次单调队列。 下面是TIE的代码。9/10&#xff1b;用了priority_queue做单调队列&#xff0c;而不是手动写的。 &#xff08;手写单调队列好麻烦~~~&#xff0c;脑子晕死&#xff0c;考试的时候过了9个点也ok&#xff0c;&#xff09; #include<iostream&…

精确率(召回率)的权衡(Machine Learning研习十六)

精确率&#xff08;召回率&#xff09;的权衡 为了理解这种权衡&#xff0c;让我们看看 SGDClassifier如何做出分类决策。 对于每个实例&#xff0c;它根据决策函数计算分数。 如果该分数大于阈值&#xff0c;则将该实例分配给正类&#xff1b; 否则它会将其分配给负类。 图 3…

独孤思维:伪造收益图,进行副业收割

01 早年独孤混群。 刚开始只会发自己的副业项目资料。 资料里面全是钩子。 所以被群主踢了。 刚开始很生气&#xff0c;后来发现自己的社群也有人打广告。 才慢慢理解那种感受。 随后混的群&#xff0c;都是以价值分享和副业心得为主。 给社群的其他小伙伴&#xff0c;…

软考高级:软件架构评估:质量属性 - 易用性 和可测试性概念和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

什么是Scala语言?

Scala 是一种多范式的编程语言&#xff0c;集面向对象编程和函数式编程的特性于一身&#xff0c;运行在 Java 虚拟机&#xff08;JVM&#xff09;上&#xff0c;并兼容现有的 Java 程序。Scala 的名字来源于 Scalable Language&#xff0c;意味着它是为了适应大型复杂软件系统的…

基于Springboot+vue的在线试题题库管理系统+数据库+报告+免费远程调试

项目介绍: Springbootvue的在线试题题库管理系统&#xff0c;Javaee项目&#xff0c;springboot vue前后端分离项目 本文设计了一个基于Springbootvue的前后端分离的在线试题题库管理系统&#xff0c;采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#x…

Github 2024-03-22 Java开源项目日报 Top10

根据Github Trendings的统计,今日(2024-03-22统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Java项目10Swift项目1Python项目1Java生态系统中的Spring框架教程集合 创建周期:3980 天开发语言:Java协议类型:MIT LicenseStar数量:35802…

git tag标签使用

创建标签 git checkout test git tag -a v1.0.0 -m v1.0.0里程碑版本 git push origin v1.0.0 删除标签 git tag -d v1.0.0 git push origin :refs/tags/v1.0.0远程分支可以直接在页面删除

【MySQL】3.1MySQL索引的介绍

目录 一、索引的概念 数据库索引 索引的作用 索引的副作用 索引创建的原则&#xff08;应用场景&#xff09; 适合建立索引 二、索引的分类和创建 1.普通索引 创建普通索引 1.1直接创建 1.2修改表结构的方式创建普通索引 1.3创建表时创建普通索引 2.唯一索引 2.1…

[python]bar_chart_race绘制动态条形图

最近在 B 站上看到了一个宝藏 up 主&#xff0c;名叫 "Jannchie见齐"&#xff0c;专门做动态条形图相关的数据可视化。 可以看到做出的效果还是很不错的&#xff0c;但工具使用的是 JS&#xff0c;不是 Python&#xff0c;于是尝试搜索了一下&#xff0c;看看 Python…

100个openharmony开源demo:1.日历

准备用开发者手机写100个开源的demo不知道能不能实现&#xff0c;日拱一卒&#xff0c;期待蜕变。 第一个demo&#xff1a;日历&#xff0c;借鉴了网上的日历算法&#xff0c;自己用arkts写了界面和点击事件&#xff0c;各位可根据此demo写自己的日历选择器等组件。 1.目录结…

Vue3、element-plus和Vue2、elementUI的一些转换

插槽 Vue3<template #default"scope"></template> <template #footer></template>Vue2<template slot-scope"scope"></template> <template slot"footer"></template>JS定义 Vue3 <script…

【5G NR 协议解读】3GPP TS 38.212 (R18) 复用和信道编码(二)

前言 本文基于3GPP TS 38.212 (R18) 复用和信道编码协议。 本文档规定了5G NR的编码、多路复用和物理信道映射。 5 总体流程 来自/去往MAC层的数据流和控制流会进行编码/解码&#xff0c;以便通过无线传输链路提供传输和控制服务。信道编码方案是错误检测、错误纠正、速率匹配…

ISO 8601:日期和时间的国际标准

ISO 8601 介绍 ISO 8601&#xff0c;介绍一下 ISO 8601 是由国际标准化组织&#xff08;International Organization for Standardization&#xff0c;ISO&#xff09;发布的国际标准&#xff0c;其全称为《数据存储和交换形式信息交换日期和时间的表示方法》。 这一标准提供了…

【网站项目】293学生用品采购系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

供应链投毒预警 | 恶意Py组件tohoku-tus-iot-automation开展窃密木马投毒攻击

概述 上周&#xff08;2024年3月6号&#xff09;&#xff0c;悬镜供应链安全情报中心在Pypi官方仓库&#xff08;https://pypi.org/&#xff09;中捕获1起新的Py包投毒事件&#xff0c;Python组件tohoku-tus-iot-automation 从3月6号开始连续发布6个不同版本恶意包&#xff0c…

【Docker】常用命令 docker search

文章目录 什么是docker search命令基本用法实际示例在Docker Hub搜索名为nginx的镜像搜索包含Python的镜像 常用选项--filter&#xff1a;过滤搜索结果--limit&#xff1a;限制搜索结果数量 总结 在Docker中&#xff0c; docker search命令是用于从Docker Hub或其他镜像仓库搜…

【Python 48小时速成 12】类和对象

在 Python 中&#xff0c;类是一种用于创建对象的蓝图或模板&#xff0c;而对象是根据类创建的实例。类定义了对象的属性和方法。下面是一个简单的类和对象的示例代码&#xff1a; # 定义一个名为 Person 的类 class Person:# __init__ 方法用于初始化对象的属性def __init__(…