Mock进行单元测试_单体测试用mock吗-程序员宅基地

技术标签: 开发中常见的一些方法  


中文文档参考地址,点击这里
汪文君Mockito实战视频
汪文君Mockito源码,点击这里
参考文章

@InjectMocks

用来修饰被测试的类:就是对哪个类中的方法进行单元测试的时候,就用该注解修饰这个类。

  • InjectMocks创建这个类的对象并自动标记@Mock,@Spy等注解的属性注入到这个中。
  • 要求必须是类不能是接口。

使用

步骤:

  1. 环境使用mock和test包
  2. 使用mockitoRule构造mockito环境
@Rule

public MokitoRule rule = MockitoJUnit.rule();

注意这里的修饰符public,如果没有这个修饰符的话使用mock测试会报错

 @Rule

 public ExpectedException thrown = ExpectedException.none();

可以选择忽视抛出的异常?(我是这么理解的不知道是否正确)

  1. 对目标测试类加@InjectMocks注解
  2. 对目标测试类的依赖属性使用@mock创建依赖
  3. 使用@test注解测试目标类的方法执行逻辑
    2mock对象创建和目标测试类的依赖注入
    这里我还没有看juint执行的逻辑,只是看了mock环境下获取注解创建mock对象,并将mock的对向注入到@Injectmocks的目标测试对象中去的逻辑。

1.Maven

<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-all</artifactId>
        <version>2.0.2-beta</version>
    </dependency>
       <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>

2.创建Mock对象

1.通过方法创建

/**
 * @description: 使用Mockito启动器进行单元测试
 * @author: wei·man cui
 * @date: 2020/8/13 11:08
 */
@RunWith(MockitoJUnitRunner.class)
public class MockitoByRunnerTest {
    

    @Test
    public void testMock() {
    
        //通过方法的模式,Mock一个对象
        AccountDao accountDao = Mockito.mock(AccountDao.class);
        // 不会报错,但返回null。不会真正执行 accountDao.findAccount()方法,只是模拟该行为。
        Account account = accountDao.findAccount("x", "y");
        System.out.println(account);
    }

}

2.通过注解创建

/**
 * @description: Annotation方式进行Mock
 * @author: wei·man cui
 * @date: 2020/8/13 11:22
 */
public class MockByAnnotationTest {
    

    @Before
    public void init() {
    
        MockitoAnnotations.initMocks(this);
    }

    @Mock
    private AccountDao accountDao;

    @Test
    public void testMock() {
    
        Account account = accountDao.findAccount("x", "y");
        System.out.println(account);
    }

}

一个简单的例子:

package Mockito;

import org.junit.Assert;
import org.junit.Test;
import java.util.List;

import static org.mockito.Mockito.*;

public class MyTest {
    
    @Test
    public void myTest() {
    
        /* 创建 Mock 对象 */
        List list = mock(List.class);
        /* 设置预期,当调用 get(0) 方法时返回 "111" */
        when(list.get(0)).thenReturn("111");

        Assert.assertEquals("asd", 1, 1);
        /* 设置后返回期望的结果 */
        System.out.println(list.get(0));
        /* 没有设置则返回 null */
        System.out.println(list.get(1));

        /* 对 Mock 对象设置无效 */
        list.add("12");
        list.add("123");
        /* 返回之前设置的结果 */
        System.out.println(list.get(0));
        /* 返回 null */
        System.out.println(list.get(1));
        /* size 大小为 0 */
        System.out.println(list.size());

        /* 验证操作,验证 get(0) 调用了 2 次 */
        verify(list, times(2)).get(0);

        /* 验证返回结果 */
        String ret = (String)list.get(0);
        Assert.assertEquals(ret, "111");
   }

在这里插入图片描述
从上面代码能看出一般使用的步骤:

设置方法预期返回
通过 when(list.get(0)).thenReturn(“111”); 来设置当调用 list.get(0) 时返回 “111”,该方法就是 Stub,替换我们实际的操作。

验证方法调用
该方法验证 get(0) 方法调用的次数 verify(list, times(2)).get(0);,还可以设置是否调用过,调用时间等等。

验证返回值
Assert.assertEquals(ret, “111”); 方法验证 Mock 对象方法调用后的返回值是否达到预期。


Spy

Mock构造一个List对象的时候,使用add是无效的(代表对象的真正的方法),只有使用Spy的时候才能使之生效。
代码如下所示:

   @RunWith(MockitoJUnitRunner.class)
public class SpyingTest {
    

    /**
     * Spy:用于部分方法的 Mock(模拟)
     */
    @Test
    public void testSpy() {
    
        List<String> realList = new ArrayList<>();
        List<String> list = Mockito.spy(realList);

        list.add("Mockito");
        list.add("PowerMock");
        assertThat(list.get(0), equalTo("Mockito"));
        assertThat(list.get(1), equalTo("PowerMock"));
        assertThat(list.isEmpty(), equalTo(false));

        // Stubbing 语法 模拟 list 的返回内容
        Mockito.when(list.isEmpty()).thenReturn(true);
        Mockito.when(list.size()).thenReturn(0);

        assertThat(list.get(0), equalTo("Mockito"));
        assertThat(list.get(1), equalTo("PowerMock"));
        assertThat(list.isEmpty(), equalTo(true));
        assertThat(list.size(), equalTo(0));
    }

}

或者使用注解的方式:

public class SpyingAnnotationTest {
    

    @Spy
    private List<String> list = new ArrayList<>();

    @Before
    public void init() {
    
        MockitoAnnotations.initMocks(SpyingAnnotationTest.class);
    }

    @Test
    public void testSpy() {
    
        list.add("Mockito");
        list.add("PowerMock");
        assertThat(list.get(0), equalTo("Mockito"));
        assertThat(list.get(1), equalTo("PowerMock"));
        assertThat(list.isEmpty(), equalTo(false));

       // Stubbing 语法 模拟 list 的返回内容
        Mockito.when(list.isEmpty()).thenReturn(true);
        Mockito.when(list.size()).thenReturn(0);

        assertThat(list.get(0), equalTo("Mockito"));
        assertThat(list.get(1), equalTo("PowerMock"));
        assertThat(list.isEmpty(), equalTo(true));
        assertThat(list.size(), equalTo(0));
    }

}

我认为比较好的一种方式:

下面是Mockito具体使用的一些示例:

mock外部依赖对象,并注入到我们的业务类中,以便在单元测试中进行模拟调用:

@RunWith(MockitoJUnitRunner.class) //让测试运行于Mockito环境
public class LocalServiceImplMockTest {
    

    @InjectMocks    //此注解表示这个对象需要被注入mock对象
    private LocalServiceImpl localService;
    @Mock   //此注解会自动创建1个mock对象并注入到@InjectMocks对象中
    private RemoteServiceImpl remoteService;

    //如果不使用上述注解,可以使用@Before方法来手动进行mock对象的创建和注入,但会几行很多代码
    /*
    private LocalServiceImpl localService;
    private RemoteServiceImpl remoteService;

    @Before
    public void setUp() throws Exception {
        localService = new LocalServiceImpl();
        remoteService = Mockito.mock(RemoteServiceImpl.class);  //创建Mock对象
        Whitebox.setInternalState(localService, "remoteService", remoteService); //注入依赖对象
    }
    */

    @Test
    public void testMock() {
    
        Node target = new Node(1, "target");    //创建一个Node对象作为返回值
        Mockito.when(remoteService.getRemoteNode(1)).thenReturn(target); //指定当remoteService.getRemoteNode(int)方法传入参数为1时返回target对象
        Node result = localService.getRemoteNode(1);    //调用我们的业务方法,业务方法内部调用依赖对象方法
        assertEquals(target, result);   //可以断言我们得到的返回值其实就是target对象
        assertEquals(1, result.getNum());   //具体属性和我们指定的返回值相同
        assertEquals("target", result.getName());   //具体属性和我们指定的返回值相同

        Node result2 = localService.getRemoteNode(2);   //未指定参数为2时对应的返回规则
        assertNull(result2);    //未指定时返回为null
    }
}

1.spy外部依赖对象,并注入到我们的业务类中:

@RunWith(MockitoJUnitRunner.class)
public class LocalServiceImplSpyTest {
    

    @InjectMocks
    private LocalServiceImpl localService;
    @Spy    //注意这里使用的是@Spy注解
    private RemoteServiceImpl remoteService;
    //注意如果自己创建spy对象的话要这么写:
    /*
        remoteService = new RemoteServiceImpl();    //先创建一个具体实例
        remoteService = Mockito.spy(remoteService);   //再调用Mockito.spy(T)方法创建spy对象
    */

    @Test
    public void testSpy() {
    
        Node target = new Node(1, "target");    //创建一个Node对象作为返回值
        Mockito.when(remoteService.getRemoteNode(1)).thenReturn(target); //指定当remoteService.getRemoteNode(int)方法传入参数为1时返回target对象
        Node result = localService.getRemoteNode(1);    //调用我们的业务方法,业务方法内部调用依赖对象方法
        assertEquals(target, result);   //可以断言我们得到的返回值其实就是target对象
        assertEquals(1, result.getNum());   //具体属性和我们指定的返回值相同
        assertEquals("target", result.getName());   //具体属性和我们指定的返回值相同

        Node result2 = localService.getRemoteNode(2);   //未指定参数为2时的调用规则,所以会直接调用真实对象,返回remote创建的节点
        assertEquals(2, result2.getNum());
        assertEquals("Node from remote service", result2.getName());    //remoteService创建Node对象时设置name属性为"Node from remote service"
    }
}

1.使用ArgumentMatchers的any系列方法指定多种返回值,有any()、anyInt()、anyString()、anyByte()、anyLong()等等,可以看下ArgumentMatchers类源码中定义的所有方法:

    @Test
    public void testAny() {
    
        Node target = new Node(1, "target");
        when(remoteService.getRemoteNode(anyInt())).thenReturn(target); //静态导入Mockito.when和ArgumentMatchers.anyInt后可以简化代码提升可读性

        Node result = localService.getRemoteNode(20); //上面指定了调用remoteService.getRemoteNode(int)时,不管传入什么参数都会返回target对象
        assertEquals(target, result);   //可以断言我们得到的返回值其实就是target对象
        assertEquals(1, result.getNum());   //具体属性和我们指定的返回值相同
        assertEquals("target", result.getName());   //具体属性和我们指定的返回值相同
    }

指定mock对象多次调用的返回值:

    /**
     * 指定mock多次调用返回值
     */
    @Test
    public void testMultipleReturn() {
    
        Node target1 = new Node(1, "target");
        Node target2 = new Node(1, "target");
        Node target3 = new Node(1, "target");
        when(remoteService.getRemoteNode(anyInt())).thenReturn(target1).thenReturn(target2).thenReturn(target3);
        //第一次调用返回target1、第二次返回target2、第三次返回target3

        Node result1 = localService.getRemoteNode(1); //第1次调用
        assertEquals(target1, result1);
        Node result2 = localService.getRemoteNode(2); //第2次调用
        assertEquals(target2, result2);
        Node result3 = localService.getRemoteNode(3); //第3次调用
        assertEquals(target3, result3);
    }
指定mock对象抛出异常(注意如果方法中未声明会抛出异常,只能指定抛出运行时异常,如果仍指定为抛出受检查异常,运行时会报错误org.mockito.exceptions.base.MockitoException: Checked exception is invalid for this method!):
    //RemoteServiceImpl方法:
    @Override
    public Node getRemoteNode(String name) throws MockException {
    
        if (StringUtils.isEmpty(name)) {
    
            throw new MockException("name不能为空", name);
        }
        return new Node(name);
    }

    //LocalServiceImpl方法
    @Override
    public Node getRemoteNode(String name) throws MockException {
    
        try {
    
            return remoteService.getRemoteNode(name);
        } catch (IllegalArgumentException e) {
    
            throw e;
        }
    }

    /**
     * 指定mock对象已声明异常抛出的方法抛出受检查异常
     */
    @Test
    public void testExceptionDeclare() {
    
        try {
    
            Node target = new Node(1, "target");
            when(remoteService.getRemoteNode("name")).thenReturn(target).thenThrow(new MockException(
                    "message", "exception")); //第一次调用正常返回,第二次则抛出一个Exception

            Node result1 = localService.getRemoteNode("name");
            assertEquals(target, result1); //第一次调用正常返回

            Node result2 = localService.getRemoteNode("name"); //第二次调用不会正常返回,会抛出异常
            assertEquals(target, result2);
        } catch (MockException e) {
    
            assertEquals("exception", e.getName()); //验证是否返回指定异常内容
            assertEquals("message", e.getMessage()); //验证是否返回指定异常内容
        }
    }

    /**
     * 指定mock对象为声明异常抛出的方法抛出运行时异常
     */
    @Test
    public void testRuntimeException() {
    
        Node target = new Node(1, "target");
        when(remoteService.getRemoteNode(1)).thenThrow(new RuntimeException("exception")); //指定调用时抛出一个运行时异常

        try {
    
            Node result = localService.getRemoteNode(1);
            assertEquals(target, result);
        } catch (RuntimeException e) {
    
            assertEquals("exception", e.getMessage());
        }
    }

    /**
     * 指定mock对象未声明异常抛出的方法抛出受检查异常,以下方法执行会报错
     */
    @Test
    public void testNotDefineCheckedException() {
    
        Node target = new Node(1, "target");
        when(remoteService.getRemoteNode(1)).thenThrow(new IOException("io exception"));

        try {
    
            Node result = localService.getRemoteNode(1);
            assertEquals(target, result);
        } catch (Exception e) {
    
            assertEquals("io exception", e.getMessage());
        }
    }
mock void方法抛异常、什么都不做:
    //RemoteServiceImpl方法:
    @Override
    public void doSometing() {
    
        System.out.println("remote service do something!");
    }

    //LocalServiceImpl方法
    @Override
    public void remoteDoSomething() {
    
        remoteService.doSometing();
    }

    //注意void方法没有返回值,所以mock规则写法顺序不一样
    doNothing().when(remoteService).doSometing();
    doThrow(new RuntimeException("exception")).when(remoteService).doSometing();

校验mock对象的调用情况(除Mockito中的never()、times(int)方法外,还有atLeast(int)、atLeastOne()、atMost(int)等方法):

   /**
     * 校验mock对象和方法的调用情况
     *
     */
    public void testVerify() {
    
        Node target = new Node(1, "target");
        when(remoteService.getRemoteNode(anyInt())).thenReturn(target);

        verify(remoteService, never()).getRemoteNode(1); //mock方法未调用过

        localService.getRemoteNode(1);
        Mockito.verify(remoteService, times(1)).getRemoteNode(anyInt()); //目前mock方法调用过1次

        localService.getRemoteNode(2);
        verify(remoteService, times(2)).getRemoteNode(anyInt()); //目前mock方法调用过2次
        verify(remoteService, times(1)).getRemoteNode(2); //目前mock方法参数为2只调用过1次
    }

利用ArgumentCaptor捕获方法参数进行mock方法参数校验

    /**
     * 利用ArgumentCaptor捕获方法参数进行mock方法参数校验
     */
    @Test
    public void testCaptor() throws Exception {
    
        Node target = new Node(1, "target");
        when(remoteService.getRemoteNode(anyString())).thenReturn(target);

        localService.getRemoteNode("name1");
        localService.getRemoteNode("name2");
        verify(remoteService, atLeastOnce()).getRemoteNode(localCaptor.capture()); //设置captor

        assertEquals("name2", localCaptor.getValue()); //获取最后一次调用的参数
        List<String> list = localCaptor.getAllValues(); //按顺序获取所有传入的参数
        assertEquals("name1", list.get(0));
        assertEquals("name2", list.get(1));
    }

mock对象调用真实方法:

    /**
     * mock对象调用真实方法
     */
    @Test
    public void testCallRealMethod() {
    
        when(remoteService.getRemoteNode(anyInt())).thenCallRealMethod(); //设置调用真实方法
        Node result = localService.getRemoteNode(1);

        assertEquals(1, result.getNum());
        assertEquals("Node from remote service", result.getName());
    }

重置mock对象:

    //重置mock,清除所有的调用记录和返回规则
    Mockito.reset(remoteService);

校验mock对象0调用和未被验证的调用

    /**
     * 校验mock对象0调用和未被验证的调用
     */
    @Test(expected = NoInteractionsWanted.class)
    public void testInteraction() {
    
        verifyZeroInteractions(remoteService); //目前还未被调用过,执行不报错

        Node target = new Node(1, "target");
        when(remoteService.getRemoteNode(anyInt())).thenReturn(target);

        localService.getRemoteNode(1);
        localService.getRemoteNode(2);
        verify(remoteService, times(2)).getRemoteNode(anyInt());
        // 参数1和2的两次调用都会被上面的anyInt()校验到,所以没有未被校验的调用了
        verifyNoMoreInteractions(remoteService);

        reset(remoteService);
        localService.getRemoteNode(1);
        localService.getRemoteNode(2);
        verify(remoteService, times(1)).getRemoteNode(1);
        // 参数2的调用不会被上面的校验到,所以执行会抛异常
        verifyNoMoreInteractions(remoteService);
    }

Mockito 使用

设置 Mock 对象期望和返回值

/* 表示第一次调用 someMethod() 返回 value1 第二次调用返回 value2 */
when(mock.someMethod()).thenReturn(value1).thenReturn(value2);  
when(mock.someMethod()).thenReturn(value1, value2);  
/* 也可以设置两次 */
when(mock.someMethod()).thenReturn(value1);
when(mock.someMethod()).thenReturn(value2);

另外一种写法 doReturn()

/* 表示第一次调用 someMethod() 返回 value1 第二次调用返回 value2 */
doReturn(value1).doReturn(value2).when(mock).someMethod();  
/* 若返回 void,则设置为 doNothing() */
doNothing().when(mock).someMethod();

对方法设定返回异常

/* 当调用 someMethod() 方法时会抛出异常 */
when(mock.someMethod()).thenThrow(new RuntimeException());
/* 对 void 方法设定 */  
doThrow(new RuntimeException()).when(mock).someMethod();  

参数匹配器
我们不一定要固定 Stub 调用时的参数,如 get(0)。可以通过参数匹配器来调用。

when(list.get(anyInt())).thenReturn("hello");

不同的调用次数返回不同的值

@Test 
public void Test01(){
    
//这种方式,第一次调用返回1,第二次调用返回2,4次以后,都一直返回4.
 Mockito.when(list.size()).thenReturn(1,2,3,4);
 asertThat(list.size(),equalTo(1));
 asertThat(list.size(),equalTo(2));
 asertThat(list.size(),equalTo(3));
 asertThat(list.size(),equalTo(4));
//与上面等价的一种方式
 Mockito.when(list.size()).thenReturn(1).thenReturn(2).thenReturn(3).thenReturn(4);
}

Mock 对象的行为验证

package Mockito;

import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.testng.annotations.Test;

import java.util.List;
import static org.mockito.Mockito.*;

/**
 * Created by andy.wwh on 2016/7/18.
 */
public class Behavior {
    
    @Test
    public void behaviorCheck() {
    
        List mock1 = mock(List.class);
        List mock2 = mock(List.class);

        /* 设置预期 */
        when(mock1.get(0)).thenReturn("hello world");
        when(mock1.get(1)).thenReturn("hello world");
        when(mock2.get(0)).thenReturn("hello world");
        mock1.get(0);

        /* 验证方法调用一次 */
        verify(mock1).get(0);
        mock1.get(0);
        /* 验证方法调用两次 */
        verify(mock1, times(2)).get(0);
        /* 验证方法从未被调用过 */
        verify(mock2, never()).get(0);
        /* 验证方法 100 毫秒内调用两次 */
        verify(mock1, timeout(100).times(2)).get(anyInt());

        /* 设置方法调用顺序 */
        InOrder inOrder = inOrder(mock1, mock2);
        inOrder.verify(mock1, times(2)).get(0);
        inOrder.verify(mock2, never()).get(1);

        /*  查询是否存在被调用,但未被 verify 验证的方法 */
        verifyNoMoreInteractions(mock1, mock2);
        /* 验证 Mock 对象是否没有交发生 */
        verifyZeroInteractions(mock1, mock2);

        /* 参数捕获器 */
        ArgumentCaptor<Integer> argumentCaptor = ArgumentCaptor.forClass(Integer.class);
        verify(mock1, times(2)).get(argumentCaptor.capture());
        System.out.println("argument:" + argumentCaptor.getValue());
    }
}

验证调用次数

verify(mock1, timeout(100).times(2)).get(anyInt());

除了代码中的方法,Mockito 还提供了

  • never() 没有被调用,相当于times(0)
  • atLeast(N) 至少被调用N次
  • atLeastOnce() 相当于atLeast(1)
  • atMost(N) 最多被调用N次

超时验证
通过 timeout 我们可以进行验证程序执行时间是否符合规则。

方法调用顺序
Inorder 可以验证方法调用的顺序

verifyNoMoreInteractions 和 verifyZeroInteractions
verifyNoMoreInteractions:查询是否存在被调用,但未被 verify 验证的方法

verifyZeroInteractions:verifyZeroInteractions

ArgumentCaptor 参数捕获器
可在验证时对方法的参数进行捕获,最后验证捕获的参数值。如果方法有多个参数都要捕获验证,那就需要创建多个ArgumentCaptor对象处理。


Spy 对象验证

Mock 操作的全是虚拟对象。即使我们设置了 when(list.get(0)).thenReturn(1),我们调用如 size() 方法返回的还是 0。Mockito 还给我们提供了一种对真实对象操作的方法——Spy

做一个简单的比较:

package Mockito;

import org.testng.annotations.Test;

import java.util.List;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/**
 * Created by andy.wwh on 2016/7/18.
 */
public class MockObject {
    
    @Test
    public void MockTest() {
    
        List list = mock(List.class);

        when(list.get(0)).thenReturn("hello world");

        System.out.println(list.get(0));

        System.out.println(list.size());
    }
}

在这里插入图片描述

package Mockito;

import org.testng.annotations.Test;

import java.util.LinkedList;
import java.util.List;

import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

/**
 * Created by andy.wwh on 2016/7/18.
 */
public class MockObject {
    
    @Test
    public void MockTest() {
    
        /* 创建真实对象 */
        List list = new LinkedList();
        List spy = spy(list);

        spy.add("hello");

        when(spy.get(0)).thenReturn("hello world");

        System.out.println(spy.get(0));
    }
}

看个官网的例子:

@Test  
public void spyTest() {
      
    List list = new LinkedList();  
    List spy = spy(list);  
    // optionally, you can stub out some methods:  
    when(spy.size()).thenReturn(100);  
    // using the spy calls real methods  
    spy.add("one");  
    spy.add("two");  
    // prints "one" - the first element of a list  
    System.out.println(spy.get(0));  
    // size() method was stubbed - 100 is printed  
    System.out.println(spy.size());  
    // optionally, you can verify  
    verify(spy).add("one");  
    verify(spy).add("two");  
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_42030357/article/details/113807290

智能推荐

2023.8DataWhale_cv夏令营第三期笔记_逻辑回归需要训练很多轮么-程序员宅基地

文章浏览阅读257次。使用官方提供的脑PET数据集,构建逻辑回归模型来进行脑PET图像的疾病预测,数据集被分为两类,分别为轻度认知障碍(MCI)患者的脑部影像数据和健康人(NC)的脑部影像数据,图像数据格式为nii,因此本赛题可抽象为一个二分类问题。nii是一种常用的医学图像数据格式,主要用于存储和交换神经影像数据。以下是一些主要特点:1.主要用于存储3D(三维)医学图像数据,如MRI(磁共振成像)和CT(计算机断层扫描)图像。2.支持多种数据类型,使得其可以支持不同类型的数据处理和分析。_逻辑回归需要训练很多轮么

通用指南-营销和设计中的增强现实(AR)-程序员宅基地

文章浏览阅读1.2k次,点赞31次,收藏26次。增强现实通常被视为一个利基领域。然而,在过去的两年里,它已经到了一个成熟的阶段,应该在一般的营销堆栈中进行考虑。正如我们所看到的,这个市场是巨大的,而且随着主要参与者向这项技术投入大量投资,它只会继续增长。从苹果到Meta,大公司都相信身临其境的未来,而想要获得成功的营销人员和创意人员也加入了进来。本文第三章,最佳设计实践除了深入讨论AR设计的原则外,还全面推荐了AI设计工具。旨在帮助读者的AI作品脱颖而出。

linux c 网络编程_usage: ./tcp_client hostname-程序员宅基地

文章浏览阅读473次。OSI七层网络模型由下至上为1至7层,分别为:物理层(Physical layer),数据链路层(Data link layer),网络层(Network layer),传输层(Transport layer),会话层(Session layer),表示层(Presentation layer),应用层(Application layer)。1.1 应用层,很简单,就是应用程序。这一层负责_usage: ./tcp_client hostname

Nexus3配置yum代理 pypi代理和npm代理(三合一)_maximum component age-程序员宅基地

文章浏览阅读2.8k次。环境准备安装 maven 安装 java 环境[root@cicd-nexus ~]# wget http://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz[root@cicd-nexus ~]# tar xf apache-maven-3.6.3-bin.tar.gz -C /usr/local/[root@cicd-nexus ~]# tar xf _maximum component age

使用js-xlsx handsontable 分批次导入Excel数据(兼容ie9)_js 导excel 分批写入-程序员宅基地

文章浏览阅读1.6k次。使用js-xlsx handsontable 可以把本地excel 解析到网页上,然后分批次传入后台。在chrome 下 可以参考 https://github.com/SheetJS/js-xlsx 【Browser file upload form element】但需要使用FileReader api 这个只有ie10 才开始支持。兼容ie9 ,ie9需要通过flash 来支持..._js 导excel 分批写入

wxWidgets 自绘按钮(图片+文字)_wxwidgets 中文按钮-程序员宅基地

文章浏览阅读2.5k次。在wxWidgets中,想要通过其本身的控件来实现图片+文件的按钮,貌似不太容易做到。但是可以通过重载wxControl来自绘图片+文件按钮。下面给出的是已经封装好的按钮类:wxBitmapButtonEx.h#ifndef _BITMAP_BUTTON_EX_H#define _BITMAP_BUTTON_EX_H#include "wx/wx.h"enum eBitm_wxwidgets 中文按钮

随便推点

invalidate()和postInvalidate()的区别_postinvalidate和invalidate的区别-程序员宅基地

文章浏览阅读847次。invalidate()与postInvalidate()都用于刷新View,主要区别是invalidate()在主线程中调用,若在子线程中使用需要配合handler;而postInvalidate()可在子线程中直接调用。postInvalidate它是向主线程发送个Message,然后handleMessage时,调用了invalidate()函数。(系统帮我们 写好了 Handle..._postinvalidate和invalidate的区别

计算机表格 求差,Excel表格中求差函数公式怎么用-程序员宅基地

文章浏览阅读9.1k次。excel数据进行分类汇总的步骤在做分类汇总前,我们需要对数据先进行排序,否则分类汇总无法进行。得到排序后的表格。点击上方工具栏中的“数据”→“分类汇总”。在弹出的对话框中选择“分类字段”→“汇总方式”→“决定汇总项”。点击确定出现数据汇总结果。Excel表格中求差函数公式使用的方法第一步:打开Excel表格,单击第一排,第三个“单元格”,也就是C1,在C1中输入“=A1-B1”;第二步:这个公式..._表格求差公式

Linux下OpenCV的安装与测试成功教程(解决E: 无法定位软件包 libjasper-dev、无法找到directory `opencv.pc‘、fatal error:“highgui.h“)_无法定位软件包 libgazebo-dev-程序员宅基地

文章浏览阅读1.5w次,点赞49次,收藏169次。前言好激动,断断续续装了两三天才装上,踩了好多坑。这里把成功安装的步骤详细写下来,如果有小伙伴需要,可以尝试一下,但我不能保证你也可以装好。首先说一下我的各个版本(不谈版本的安装教程都是耍流氓!)是用虚拟机软件:VirtualBOX6.1.30系统版本:ubuntu-20.04.3-desktop-amd64(最小安装模式,中文)OpenCV版本:4.5.5安装时间:2022.2.11下面是步骤1、进入OpenCV的官方下载地址Releases - OpenCV,下载So_无法定位软件包 libgazebo-dev

红帽子粉帽子绿帽子II(递归,递推)-程序员宅基地

文章浏览阅读320次,点赞6次,收藏10次。/是上一个的进化版,相邻的可以一样但是不能都是绿色,注意条件;~~~//仅当笔者个人备忘录使用。

解决Install Intel x86 Emulator Accelerator (HAXM installer) (revision: 7.6.5)“ failed问题-程序员宅基地

文章浏览阅读6.7k次。由于Install Intel x86 Emulator Accelerator (HAXM installer) (revision: 7.6.5)安装失败,导致我的安卓虚拟机无法启动。解决办法有一下几种:1.开机进入BIOS打开Virtual虚拟化功能,然后进入Androidstudio 的SDK manager里面安装HAXM2.关闭系统中的Hyper-v,进入控制面板的程序和功能,将Hyper-v去选即可。3.如果前面的方法都不行,那么建议你重新下载AndroidStudio最新版进行安装_intel x86 emulator

PowerBuilder的语言基础-程序员宅基地

文章浏览阅读1.1w次,点赞2次,收藏15次。 每一种语言都有一组基本的语法约定,POWERBUILDER也不例外。 (1)断行、续行与多条语句 通常情况下,powerbuilder的一条语句是写到一行上的,该条语句在书写完毕之后,按键转到下一行,开始写下一句的内容。也就是说,在PowerBuilder中,使用键作为一行的结束。在PowerBuilder语句比较长的情况下,为了方便阅读,可以使用续行符号把一条语句写到几_powerbuilder