一、前期准备~

1、准备工作

<!--mockito依赖-->a
<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")); //false
System.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)); //second
System.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>() {
@Override
public 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_2
System.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_1
System.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)); //test2
System.out.println(mockList.get(4)); //throw RuntimeException // 无打桩方法,返回默认值
System.out.println(mockList.get(99)); //null
}

3、参数匹配器

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

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

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

• 支持自定义参数匹配器;

@Test
public 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())); //value2
System.out.println(mockMap.get("test_key")); //value2
System.out.println(mockMap.get(0)); //null // 多个入参时,要么都使用参数匹配器,要么都不使用,否则会异常
when(mockMap.put(anyString(), anyInt())).thenReturn("value3");
System.out.println(mockMap.put("key3", 3)); //value3
System.out.println(mockMap.put(anyString(), anyInt())); //value3
System.out.println(mockMap.put("key3", anyInt())); //异常 // 行为验证时,也支持使用参数匹配器
verify(mockMap, atLeastOnce()).get(anyString());
verify(mockMap).put(anyString(), eq(3)); // 自定义参数匹配器
final ArgumentMatcher<ArgumentTestRequest> myArgumentMatcher = new ArgumentMatcher<ArgumentTestRequest>() {
@Override
public boolean matches(ArgumentTestRequest request) {
return "name".equals(request.getName()) || "value".equals(request.getValue());
}
};
// 自定义参数匹配器使用
final ArgumentTestService mock = mock(ArgumentTestService.class);
when(mock.argumentTestMethod(argThat(myArgumentMatcher))).thenReturn("success");
doReturn("success").when(mock).argumentTestMethod(argThat(myArgumentMatcher));
System.out.println(mock.argumentTestMethod(new ArgumentTestRequest("name", "value"))); // success
System.out.println(mock.argumentTestMethod(new ArgumentTestRequest())); //null
}

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())); //success
System.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 = paramA
System.out.println(stubTestService.stubTestMethodB()); //stubTestMethodB is called
System.out.println(stubTestService.stubTestMethodC()); //null // spy部分mock
final 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()); //100
System.out.println(spy.get(0)); //one_test
System.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: 2
System.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)); //one
arrayList.add(0, "list1");
System.out.println(arrayList.get(0)); //list1
System.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()); //100
reset(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 called
System.out.println(stubTestServiceImpl1.stubTestMethodA("spy")); //stubTestMethodA is called, param = spy // 区分是mock对象还是spy对象
System.out.println(mockingDetails(stubTestService).isMock()); //true
System.out.println(mockingDetails(stubTestService).isSpy()); //false
System.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,等等。
// 参考返回配置:ReturnsEmptyValues
mock(ArrayList.class, Answers.RETURNS_DEFAULTS); // ReturnsSmartNulls首先尝试返回普通值(0,空集合,空字符串,等等)然后它试图返回SmartNull。
// 如果最终返回对象,那么会简单返回null。一般用在处理遗留代码。
// 参考返回配置:ReturnsMoreEmptyValues
mock(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.html
mock(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>() {
@Override
public 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
public class User { /**
* 姓名,登录密码
*/

持久层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
@Autowired
private UserDao userDao; /**
* 根据name查找user
* @param name
* @return
*/
@Override
public User getUserByName(String name) {
try {
return userDao.getUserByName(name);
} catch (Exception e) {
throw new RuntimeException("查询user异常");
}
} /**
* 保存user
* @param user
* @return
*/
@Override
public 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
*/
@Test
public 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
*/
@Mock
private UserDao userDao;
@InjectMocks
private UserServiceImpl userService;
@Test
public 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); //保存结果:1
Assert.assertEquals("保存失败!", 1, integer.longValue()); verify(userDao).saveUser(any(User.class));
verify(userDao, times(2)).getUserByName(anyString());
} }

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

四、参考文档及进一步学习~

作者:京东零售 秦浩然

来源:京东云开发者社区 转载请注明来源

一文浅谈Mockito使用的更多相关文章

  1. 《浅谈我眼中的express、koa和koa2》好文留存+笔记

    原文 :三英战豪强,思绪走四方.浅谈我眼中的express.koa和koa2 一.回调大坑怎么解决呢? 1.es5可以利用一下第三方库,例如 async 库, 2.或者单纯使用 connect中间件  ...

  2. 浅谈WebService的版本兼容性设计

    在现在大型的项目或者软件开发中,一般都会有很多种终端, PC端比如Winform.WebForm,移动端,比如各种Native客户端(iOS, Android, WP),Html5等,我们要满足以上所 ...

  3. Linux特殊符号浅谈

    Linux特殊字符浅谈 我们经常跟键盘上面那些特殊符号比如(?.!.~...)打交道,其实在Linux有其独特的含义,大致可以分为三类:Linux特殊符号.通配符.正则表达式. Linux特殊符号又可 ...

  4. 浅谈Hybrid技术的设计与实现第三弹——落地篇

    前言 接上文:(阅读本文前,建议阅读前两篇文章先) 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 根据之前的介绍,大家对前端与Native的交互应该有一些简单的认识了,很多 ...

  5. 浅谈Vue.js

    作为一名Vue.js的忠实用户,我想有必要写点文章来歌颂这一门美好的语言了,我给它的总体评价是“简单却不失优雅,小巧而不乏大匠”,下面将围绕这句话给大家介绍Vue.js,希望能够激发你对Vue.js的 ...

  6. 浅谈Android应用保护(一):Android应用逆向的基本方法

    对于未进行保护的Android应用,有很多方法和思路对其进行逆向分析和攻击.使用一些基本的方法,就可以打破对应用安全非常重要的机密性和完整性,实现获取其内部代码.数据,修改其代码逻辑和机制等操作.这篇 ...

  7. 浅谈Java中的对象和引用

    浅谈Java中的对象和对象引用 在Java中,有一组名词经常一起出现,它们就是“对象和对象引用”,很多朋友在初学Java的时候可能经常会混淆这2个概念,觉得它们是一回事,事实上则不然.今天我们就来一起 ...

  8. 浅谈php生成静态页面

    一.引 言 在速度上,静态页面要比动态页面的比方php快很多,这是毫无疑问的,但是由于静态页面的灵活性较差,如果不借助数据库或其他的设备保存相关信息的话,整体的管理上比较繁琐,比方修改编辑.比方阅读权 ...

  9. 浅谈HTTPS以及Fiddler抓取HTTPS协议

    最近想尝试基于Fiddler的录制功能做一些接口的获取和处理工作,碰到的一个问题就是简单连接Fiddler只能抓取HTTP协议,关键的登录请求等HTTPS协议都没有捕捉到,所以想让Fiddler能够同 ...

  10. 浅谈五大Python Web框架

    转载:http://feilong.me/2011/01/talk-about-Python-web-framework 说到Web Framework,Ruby的世界Rails一统江湖,而Pytho ...

随机推荐

  1. 【Rust-book】第五章 使用结构体来组织相关联的数据

    第五章 使用结构体来组织相关联的数据 结构,或者结构体,是一种自定义数据类型,它允许我们命名多个相关的值并将它们组成一个有机的结合体. 可以把结构体视作对象中的数据属性 1 对比元组和结构体之间的异同 ...

  2. #PowerBi Superchange PowerBi 序言部分笔记(2)

    Xmind本文思维导图 序言部分,主要讲述了BI的分类及发展,以及作者推荐的学习方法.重点是介绍了powerbi的主要四大步骤. 即: 一:数据采集 Data acquisition: Power B ...

  3. 数据库中的可视化和探索性:MongoDB的数据可视化和探索性工具

    目录 1. 引言 2. 技术原理及概念 2.1 基本概念解释 2.2 技术原理介绍 2.3 相关技术比较 3. 实现步骤与流程 3.1 准备工作:环境配置与依赖安装 3.2 核心模块实现 3.3 集成 ...

  4. Java判断一个数是不是质数

    判断一个数是不是质数 做这个题之前我们需要先进行了解什么是质数 质数:只能被1和它本身整除的数 举一个简单的例子:数字5是不是质数呢? 我们可以进行分析: 解题思路:5可以分为1 2 3 4 5,我们 ...

  5. 屏蔽CSDN百度广告

    最近在查询一些技术问题访问到CSDN时一直弹一些令人作恶的广告,说个特别的广告,脱发广告,特别有针对性程序员同胞们的共性问题,不过还是特别恶心,百度了一下,大家也特别反感,CSDN你真这么缺钱?废话不 ...

  6. python笔记:第四章使用字典

    1.1 概述 说白了就是键值对的映射关系 不会丢失数据本身关联的结构,但不关注数据的顺序 是一种可变类型 格式:dic = {键:值, 键:值} 键的类型:字典的键可以是任何不可变的类型,如浮点数,字 ...

  7. 现代C++(Modern C++)基本用法实践:零、概述&测试项目

    序言 习惯上,我们把C++11之前的C++语法特性称之为"传统C++(traditional c++)",而把c++11之后的语法特性称之为现代C++(modern c++).有一 ...

  8. hexo博客生成报错YAMLException: can not read a block mapping entry

    报错信息: YAMLException: can not read a block mapping entry; a multiline key may not b --- title: [转]--I ...

  9. curl 调用url时带有&符号被截断

    转载请注明出处: 用curl命令在服务器上调试接口时,一直调试不通,执行如下: 在用curl 执行之后,返回了一个 作业id [ 1 ] 23926 ; 并打印出了 调用执行的url,发现 真正执行的 ...

  10. 深入Scikit-learn:掌握Python最强大的机器学习库

    本篇博客详细介绍了Python机器学习库Scikit-learn的使用方法和主要特性.内容涵盖了如何安装和配置Scikit-learn,Scikit-learn的主要特性,如何进行数据预处理,如何使用 ...