Java单测Mock升级实践

news2025/1/21 6:36:56

Java单测Mock升级实践

一、背景

众所周知,单元测试是改善代码质量,提升研发交付品质的手段之一,能否写出好的单元测试用例,也是衡量我们研发专业性的标准之一。所以,想要成为一名合格的研发,就应该要有编写单测用例的习惯,也应充分认识到单元测试的重要性。但是,往往在时间紧、任务重、降本增效等既要又要还要的高标准要求下,如何有效提升单元测试覆盖率以及单元测试质量,值得我们思考。

二、研发痛点

时间紧、任务重、资源有限是我们项目开发过程中的常态,客观上无法避免,但在编写单测实操层面还有一些痛点:

1、集成测试:

由于赶项目进度,单测并不是基于代码模块分别编写,而是基于项目启动后的接口调用,即集成测试,接口调通即认为单测通过,如果这样,接口调用顺利与否又依赖于关联方的接口是否可用,所以往往在项目最后才能跑单测,单测效用不理想。

2、数据依赖:

因为单测是集成测试,执行时需要依赖测试环境真实数据,但很多业务场景测试数据很难覆盖全面,项目上线后又由于测试数据状态的变化,原有可运行通过单测Case经常失败,倘若发布流程又依赖单测执行成功结果,就需要反复修改或直接注释掉单测,再重新打包才能发布,重新发布又有新的单测用例执行失败,继而循环往复,研发和测试都苦不堪言。

3、标准不一:

各团队使用的测试框架或参考的单测编写标准各不相同,导致同一项目单测编写的标准不一,多种框架并存,存在很多兼容问题,接入及维护成本很高。

4、流于形式:

单测编写过程中,由于各种原因,部分开发者容易形成逆反思维,认为写单测只是为了满足覆盖率或者认为浪费开发时间,而不被重视。

三、升级改造

1、解决思路:

基于上述现状和痛点,迫切需要一种解决方案来提升研发单测的编写效率,降低接入成本,同时又要能够满足研发规范对单测覆盖率的要求,以便提升单测效用,保障交付质量。

基于上述前两个痛点: 我们自然而然的想到了Mock方式,思路大致如下图,即不真实调用依赖对象,只是Mock一个假的依赖对象,然后预设一个预期返回,再执行方法得出实际结果和我们预期的输出结果做对比,从而验证我们代码的逻辑是否正确。

2、框架选型:

Mock是一个很好的思路,但是市面上那么多Mock框架,我们要使用哪一款,还是要通过各种指标横向对比后才能做决定,为此,我们对市面上常用的各种Mock框架进行了横评,对比结果详见下图:

通过横向对比,最终我们选定了广大Java开发者熟悉的,同时又和SpringBoot技术栈融合良好,基于Mockito框架实现的增强版测试框架PowerMockito,再加上我们常用的Junit作为我们的单测技术选型。

3、规范统一:

有了上述解决方案及具体的落地框架选型,我们已经迈出了坚实的第一步!

但这还不够,我们还需要明确一个具体的实施标准或者落地规范,即什么是好的单测或合格的单测?为此我们参考了现有大厂的规范,确定了我们自己的单测实施规范,具体如下:

4、具体实施:

有了解决方案并建立了统一标准和实施规范,我们就着手落地实施了,实施前我们也做了充分的评估,将现有系统中的单测用例分成了两类:

存量单测:

这个是历史单测用例,我们决定暂不改动,以便减少实际实施的成本,降低改动可能带来的风险。

增量单测:

编写单测用例时要按照新的框架和标准规范实施,这部分内容是我们关注的重点。

5、实施细节:

为了提升单测落地实施的重要性,我们特地进行了内部分享和宣讲,制订了《单测Mock升级手册》供大家实际接入时参考,在手册中明确了各种单测覆盖的场景和Case示例,具体内容如下:

5.1 引入jar包:

<properties>

    <powermock.version>2.0.2</powermock.version>

    <mockito.version>2.23.4</mockito.version>

</properties>

<dependencies>

<!-- for mock test start-->

<dependency>

<groupId>org.mockito</groupId>

<artifactId>mockito-core</artifactId>

<version>${mockito.version}</version>

</dependency>

<dependency>

<groupId>org.powermock</groupId>

<artifactId>powermock-module-junit4</artifactId>

<version>${powermock.version}</version>

</dependency>

<dependency>

<groupId>org.powermock</groupId>

<artifactId>powermock-api-mockito2</artifactId>

<version>${powermock.version}</version>

</dependency>

<!-- for mock test end-->

</dependencies>

Module中引用,scope范围为test:

<!-- for mock test start -->

<dependency>

<groupId>org.mockito</groupId>

<artifactId>mockito-core</artifactId>

<scope>test</scope>

</dependency>

<dependency>

<groupId>org.powermock</groupId>

<artifactId>powermock-module-junit4</artifactId>

<scope>test</scope>

</dependency>

<dependency>

<groupId>org.powermock</groupId>

<artifactId>powermock-api-mockito2</artifactId>

<scope>test</scope>

</dependency>

<!-- for mock test end -->

5.2 Mock用例编写:

a. 如何运行单测:

@RunWith(PowerMockRunner.class) :表明用 PowerMockerRunner来运行测试用例,否则无法使用PowerMock。

@PrepareForTest({XXX.class}):所有需要测试的类,列在此处,以逗号分隔。

b. mock、spy的区别:

mock出来的对象,所有的属性、方法都会被置空,如果直接调用原本方法,会直接返回返回值类型对应的默认初始值,并不会执行方法体,通过 CallRealMethod 才能调用原方法。

spy出来的对象,是在目标对象或真实对象的基础上进行包装,可以直接调用原方法,不需要借助 CallRealMethod。

mock出来的对象可以使用 when…then… 或 do…when;

spy出来的对象只能使用 do…when,使用 when…then… 不会报错,但会先执行真实方法,再把 thenReturn 的 mock 数据替代原返回值进行返回,没有达到mock的效果。

建议 mock 一律使用 when…then,spy 一律使用 do…when,避免混淆。

c. 如何测试一个类:

要测哪个类的方法,单测类中哪个类就用@InjectMocks 注解,这个类的方法内依赖的帮助类(xxxService、xxxBusiness、xxxAO)需要被Mock,用@Mock注解。

5.3 单测示例:

5.3.1 Controller层单测:

示例中要测试UserGrayController中的userProfileConfig方法。

@RunWith(PowerMockRunner.class)

public class UserGrayServiceImplTest {

    @Mock

    private ApplicationConfigService configService;

    @Mock

    private UserGrayBusiness userGrayBusiness;

    @Mock

    private UserAccountBusiness userAccountBusiness;

    @InjectMocks

    private UserGrayServiceImpl userGrayService;

    @Test

    public void testUserProfileConfig() throws Exception {

        ProfilePagesGrayConfigRequest request = new ProfilePagesGrayConfigRequest();

        request.setUserId(123456);

        request.setPageId("1");

        request.setBizId("1111");

        request.setUserId(1111);

        UserProfileTopTextDTO configTopText = new UserProfileTopTextDTO();

        configTopText.setPageId("1");

        configTopText.setDynamicRandomMin(0d);

        configTopText.setDynamicRandomMax(1d);

        configTopText.setBizId("1111");

        List<Object> configGrayList = new ArrayList<>();

        configGrayList.add(configTopText);

        when(configService.queryListByCmp(anyString(), anyString(), any())).thenReturn(configGrayList);

    when(userAccountBusiness.queryOpenUniqueId(anyInt())).thenReturn("123456");

        when(userGrayBusiness.isRandomGray(anyInt(), anyString(), anyString())).thenReturn(true);

        when(userGrayBusiness.isHitIdCardNewUIGray(anyInt(), anyString())).thenReturn(true);

        ProfilePagesGrayConfigResponse response = userGrayService.userProfileConfig(request);

        Assert.assertTrue(response.getIdCardNewUI());

    }

}

5.3.2 Service层单测:

@RunWith(PowerMockRunner.class)

public class UserGrayServiceImplTest {

    @Mock

    private ApplicationConfigService configService;

    @Mock

    private UserGrayBusiness userGrayBusiness;

    @Mock

    private UserAccountBusiness userAccountBusiness;

    @InjectMocks

    private UserGrayServiceImpl userGrayService;

    @Test

    public void testUserProfileConfig() throws Exception {

        ProfilePagesGrayConfigRequest request = new ProfilePagesGrayConfigRequest();

        request.setUserId(123456);

        request.setPageId("1");

        request.setBizId("1111");

        request.setUserId(1111);

        UserProfileTopTextDTO configTopText = new UserProfileTopTextDTO();

        configTopText.setPageId("1");

        configTopText.setDynamicRandomMin(0d);

        configTopText.setDynamicRandomMax(1d);

        configTopText.setBizId("1111");

        List<Object> configGrayList = new ArrayList<>();

        configGrayList.add(configTopText);

        when(configService.queryListByCmp(anyString(), anyString(), any())).thenReturn(configGrayList);

    when(userAccountBusiness.queryOpenUniqueId(anyInt())).thenReturn("123456");

        when(userGrayBusiness.isRandomGray(anyInt(), anyString(), anyString())).thenReturn(true);

        when(userGrayBusiness.isHitIdCardNewUIGray(anyInt(), anyString())).thenReturn(true);

        ProfilePagesGrayConfigResponse response = userGrayService.userProfileConfig(request);

        Assert.assertTrue(response.getIdCardNewUI());

    }

}

5.3.3 DAO 层Mock单测:

@Test

public void testBatchSave() {

    List<BusinessOpportunityExtend> inputList = ResourceFileUtil

                    .readForList("data/OpportunityExtend/batch_save_list.json", BusinessOpportunityExtend.class);

    PowerMockito.doAnswer((Answer<Integer>) invocationOnMock -> {

            BusinessOpportunityExtend extend = invocationOnMock.getArgument(0);

            extend.setId(2L);

            return 1;

    }).when(dao).insert(inputList.get(0));

    Mockito.when(dao.update(Mockito.any())).thenReturn(1);

    assert service.batchSave(inputList).getContent() == inputList.size();

}

5.3.4 特殊场景Mock单测

1)  静态方法Mock:

@RunWith(PowerMockRunner.class)

@PrepareForTest({ValidateGrayUtil.class})

public class ProcessServiceMockTest {

    @Test

    public void xyzUnionLoginUrlNullTest(){

        PowerMockito.mockStatic(ValidateGrayUtil.class);

        PowerMockito.when(ValidateGrayUtil.filterUser(anyList(),anyObject(),anyObject(),anyString())).thenReturn(Arrays.asList(new xyzCheckGray()));

       

        assertEquals("2",response.getResult().toString());

    }

}

2) 私有方法Mock:

方式一(推荐):

Whitebox.invokeMethod(csdAuthAO, "hitPromotionCheckGray", request);

方式二:

目标代码:

public class MockPrivateClass {

    private String returnTrue() {

        return "return true";

    }

}

单测代码:

@RunWith(PowerMockRunner.class)

@PrepareForTest(MockPrivateClass.class)

public class PowerMockTest {

    @Test

    public void testPrivateMethod() throws Exception {

        MockPrivateClass  mockPrivateClass = PowerMockito.mock(MockPrivateClass.class);

       

        PowerMockito.when(mockPrivateClass, "returnTrue").thenReturn(false);

        PowerMockito.when(mockPrivateClass.isTrue()).thenCallRealMethod();

       

       assertThat(mockPrivateClass.isTrue(), is(false));

    }

}

3) 构造方法单测:

目标代码:

//构造方法所在类:

public class User {

    private String username;

    private String password;

    public User(String username, String password) {

        this.username = username;

        this.password = password;

    }

   

    public User() {

      

    }

    public void insert() {

        throw new UnsupportedOperationException();

    }

}

//使用构造方法的类:

public class UserService {

    public void saveUser(String username, String password) {

        User user = new User(username, password);

        user.insert();

    }

}

单测代码:

注意:

1、首先我们要注意的是在@PrepareForTest后面的是使用构造函数的类,而不是构造函数所在的类。

2、使用下面的语句对构造函数进行mock,即当new User.class类且参数为username和password时返回user这个已经mock的对象。

@RunWith(PowerMockRunner.class)

@PrepareForTest({UserService.class})

public class UserServiceTest {

    @Mock

    private User user;

    @Test

    public void testSaveUser() throws Exception {

        String username = "user1";

        String password = "aaa";

       

        //有参构造

        PowerMockito.whenNew(User.class).withArguments(username, password).thenReturn(user);

        //无参构造

        PowerMockito.whenNew(User.class).withNoArguments().thenReturn(user);

     

        PowerMockito.doNothing().when(user).insert();

        UserService userService = new UserService();

        userService.saveUser(username, password);

        Mockito.verify(user).insert();

    }

}

4) void方法单测:

目标代码:

@Component

public class UserDao{

    @Autowired

    private UserMapper userMapper

    @Autowired

    private SystemErrorRecoder systemErrorRecoder

   

    public void putUser(UserDTO userDto){

        try{

             userMapper.putUser(userDto);

        }catch(DataAccessException e){

             systemErrorRecoder.addMsgError(e.getMessage());

        }

    }

}

单测代码:

核心思路: 通过Mockito.verify来验证返回值void方法是否被执行过。

@RunWith(PowerMockRunner.class)  

@PowerMockIgnore("javax.management.*")   //解决报错previously initiated loading for different type with name "javax/managemen

public class UserDaoTest[

    private UserDao userDao;

    private UserMapper userMappers;

    private SystemErrorRecoder systemErrorRecoder;

   

    //@Test代码执行前执行,用于初始化

    @Before

    public void setUp(){

        userDao = new UserDao();

        //mock获得UserMapper类的代理对象

        userMappers = PowerMockito.mock(UserMapper.class)

       

        systemErrorRecoder = PowerMockito.mock(SystemErrorRecoder.class)

       

        //为本类的userDao对象的私有属性userMapper赋值userMappers

        Whitebox.setInternalState(userDao,"userMapper",userMappers)

               

    Whitebox.setInternalState(userDao,"systemErrorRecoder",systemErrorRecoder)

    }

   

    @Test

    public void testPutUser(){

        UserDTO user = new UserDTO();

              

        //主要代码

    PowerMockito.doNothing().when(userMappers).putUser(Mockito.any(UserDTO.class));

       

        userDao.putUser(user);

        //d.verify验证

       Mockito.verify(userMappers).putUser(Mockito.any(UserDTO.class));

       

        //a.对异常打桩

        DataAccessException exception = PowerMockito.mock(DataAccessException.class);

       

        //b.模拟try内的方法,doThrow异常

    PowerMockito.doThrow(exception).when(userMappers).putUser(Mockito.any(UserDTO.class));

       

        //c.模拟catch内的方法(如果catch内不涉及别的方法,可以省略)

    PowerMockito.doNothing().when(systemErrorRecoder).addMsgError(Mockito.anyString())

       

           

        userDao.putUser(user);

               

        //d.verify验证

    Mockito.verify(systemErrorRecoder).addMsgError(Mockito.anyString());

5) 异常单测:

@RunWith(PowerMockRunner.class)

@PrepareForTest({UserUtil.class})

public class SysUserUtilTest{

    @Test

    public void testGetSysUser() throws DataAccessException{

        //a.对异常打桩

        DataAccessException exception = PowerMockito.mock(DataAccessException.class);

       

        //b.mockststic静态类

        PowerMockito.mockStatic(UserUtil.class);

       

        //c.thenThrow覆盖异常

    PowerMockito.when(UserUtil.getSysUser(Mockito.anyString())).thenThrow(exception);    // 重点

       

        //d.断言真实对象调用结果

        Assert.assertNull(SysUserUtil.getSysUser("test"));

    }

}

6) 真实方法调用:

Service spy = PowerMockito.spy(Service.class);

//直接调用方法时真实调用

spy.method(parameters);

//使用thenReturn 会真实调用,但返回值使用mock

PowerMockito.when(spy.method(parameters)).thenReturn(someObject);

Foo mock = mock(Foo.class);

doCallRealMethod().when(mock).someMethod(params);

// 会执行真实方法

mock.someMethod(params);

注意: 使用doReturn 不会真实调用方法

PowerMockito.doReturn(someObject).when(spy).method(someObject);

7) 验证方法是否被执行过:

@Test

public void testMockitoBehavior() {

        Person person = mock(Person.class);

        int age = person.getAge();

       

        //验证getAge动作有没有发生

        verify(person).getAge();

     

         //验证person.getName()是不是没有调用

        verify(person, never()).getName();

       

        //验证是否最少调用过一次person.getAge

        verify(person, atLeast(1)).getAge();

      

        //验证getAge动作是否被调用了2次,前面只用了一次所以这里会报错

        verify(person, times(2)).getAge();

}

8) 引入Das的DAO类单测覆盖:

@RunWith(PowerMockRunner.class)

@PrepareForTest({MauPraiseRecordDAO.class, DasClientFactory.class})

public class MauPraiseRecordDAOMockTest {

    @Test

    public void testUpdateMauPraiseNumById() throws Exception {

        // Mock the DasClient object and its methods

        DasClient dasClient = PowerMockito.mock(DasClient.class);

        PowerMockito.mockStatic(DasClientFactory.class);

        PowerMockito.when(DasClientFactory.getClient("test_mau_tools")).thenReturn(dasClient);

        PowerMockito.when(dasClient.update(Mockito.any(SqlBuilder.class))).thenReturn(1);

        // Create a MauPraiseRecordDAO object and call its updateMauPraiseNumById method

        MauPraiseRecordDAO dao = new MauPraiseRecordDAO();

        int result = dao.updateMauPraiseNumById("testId", "testId", 81L);

        Assert.assertEquals(1,result);

    }

}

9) @Valid修饰的实体类属性校验(如@NotNull):

目标代码:

@Data

@ApiModel(value = "撤回点赞请求参数")

public class RecallPraiseRecordRequest {

    @ApiModelProperty(value = "点赞消息id", required = true)

    @NotNull

    Long praiseId;

}

单测代码:

private Validator validator;

    @Before

    public void setUpClass() {

        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();

        validator = factory.getValidator();

    }

     @Test

    public void validationForNullProperty() {

        // Given

        RecallPraiseRecordRequest myDto = new RecallPraiseRecordRequest();

        myDto.setPraiseId(null);

        // When

        Set<ConstraintViolation<RecallPraiseRecordRequest>> violations = validator.validate(myDto);

        // Then

        assertThat(violations).hasSize(1);

        ConstraintViolation<RecallPraiseRecordRequest> violation = violations.iterator().next();

        assertThat(violation.getPropertyPath().toString()).isEqualTo("praiseId");

    }

    @Test

    public void validationForNotNullProperty() {

        // Given

        RecallPraiseRecordRequest myDto = new RecallPraiseRecordRequest();

        myDto.setPraiseId(1L);

        // When

        Set<ConstraintViolation<RecallPraiseRecordRequest>> violations = validator.validate(myDto);

        // Then

        assertThat(violations).hasSize(0);

        ConstraintViolation<RecallPraiseRecordRequest> violation = violations.iterator().next();

        assertThat(violation.getPropertyPath().toString()).isNotEqualTo("praiseId");

    }

10)core包里面new AppclientCpData()如何覆盖:

目标代码:

public Map<String,String> checekMap(String cp){

        Map<String, String> map = new AppClientCpData(cp).getMap();

        return map;

    }

测试代码:

//测试类引入

@PrepareForTest({AESEncoderUtil.class})

@Test

public void test(){

        PowerMockito.mockStatic(AESEncoderUtil.class);

    userGrayService.checekMap("YXBwaWQ9MTAwODAwMDMmY2hhbm5lbD1BcHBTdG9yZSZkdWlkPTMzREU0NkI3NkFBQThBQjVDRUU2MkRGRTI2Njg2M0MxJmR4aWQ9MTg0MTFERDhCRkU5MjU2NkZBREMwNTBDRDUzMjAxMUMmZW49b3MlNDB1YyZvcz1CaUlVMXNVbFVCVHpMTHpKYzRqMlZzWSUyQk1aenR1Uk9yWDZiME9UMWdnSDAlM0QmcGlkPVBQRExvYW5BcHAmdWM9eGhkcnVOJTJCUnVMaXp6ZzElMkI4RTJ4JTJGRmxaR2QydkZrYU9wbWEwTXIzTmw5byUzRCZ2ZXI9NQ==");

}

11) 多线程单元测试case:

目标代码:

public abstract class AbstractSlotStyle {

@Autowired

private ApplicationConfigServiceImpl configService;

private static final Logger LOG = LoggerFactory.getLogger(AbstractSlotStyle.class);

private static final String SLOT_MIX_TYPE_MAP = "test.slot.1-2-3.materialType";

protected void packageFrontMixType(Resource resource, MaterialPO material, SlotActivatePO slotResource) {

        String slotCode = slotResource.getSlotCode();

        String mixType = material.getMixType();

        List<SlotMixTypeConfig> list = configService.queryListByCmp(SLOT_MIX_TYPE_MAP, "[]", SlotMixTypeConfig.class);

       

       if (null == list || list.isEmpty()) {

                resource.setMixType(((StyleResource) resource).fromMixType());

        }

       

        for (SlotMixTypeConfig unit : list) {

                if (null == unit.getSlotCode() || !unit.getSlotCode().equals(slotCode)) {

                        continue;

                }

                String frontMixType = unit.findMarkByValue(mixType);

                if (null == frontMixType || frontMixType.length() <= 0) {

                        resource.setMixType(((StyleResource) resource).fromMixType());

                } else {

                        resource.setMixType(frontMixType);

                }

                return;

        }

    }

}

单测代码:

@Test

public void testPackageFrontMixType() throws Exception {

        AbstractSlotStyle slotStyle = PowerMockito.spy(new AbstractSlotStyle() {});

        ApplicationConfigServiceImpl configServiceMock = PowerMockito.mock(ApplicationConfigServiceImpl.class);

        Whitebox.setInternalState(slotStyle, "configService", configServiceMock);

        String a = "[{\"slotCode\":\"fca634c37d4ec75b\",\"interTypeList\":[{\"label\":\"直接跳转\",\"value\":\"jump\"}],\"mixTypeList\":[{\"label\":\"小图+角标\",\"value\":\"smallCorner\"}]}]\n";

        PowerMockito.when(configServiceMock.queryListByCmp(test.slot.1-2-3.materialType", "[]", SlotMixTypeConfig.class))

                               .thenReturn(JSON.parseArray(a, SlotMixTypeConfig.class));

        PowerMockito.whenNew(ApplicationConfigServiceImpl.class).withNoArguments().thenReturn(configServiceMock);

        MaterialPO materialMock = Mockito.mock(MaterialPO.class);

        Mockito.when(materialMock.getMixType()).thenReturn("mixType");

        BTTEBGMCPopupResource resource = new BTTEBGMCPopupResource();

        SlotActivatePO slotActivatePO = new SlotActivatePO();

        slotActivatePO.setSlotCode("fca634c37d4ec75b");

        resource.setMixType("frontMixType");

               

        Whitebox.invokeMethod(slotStyle, "packageFrontMixType", resource, materialMock, slotActivatePO);

               

        Mockito.verify(configServiceMock).queryListByCmp("test.slot.1-2-3.materialType", "[]", SlotMixTypeConfig.class);

}

6. 实施效果:

上述方案落地实施后,实施团队增量单测覆盖率逐步上升,大家统一了标准、规范和认知,能高效的编写出一套标准一致,风格一致的单测代码了,基本解决了本文开头提到的研发单测痛点,符合预期。

另外,实施前期会有一段时间的阵痛期,总体表现为:Mock单测不会写,编写效率低下,但随着大家逐步上手,以及《单测Mock升级手册》的逐步完善,同时引入一些单测Case生成插件,后期编写效率显著提升。

四、后续规划

以上,跟大家分享了Java Mock单测的落地实施过程,后续还有一些思考和规划,总结如下:

1、如何通过单测改善现有代码

虽然我们能写好单测,但是能不能通过单测反向优化我们的代码结构,提升代码的可读性和可维护性,尽量减少代码问题的出现和发生,这可能又是我们追求的新目标。

2、利用新技术更高效的写单测

随着AI技术的盛行,能不能利用或开发一些AI组件,来帮助我们尽量减少手写单测的场景,还有单测用例的自动生成,从而让我们单测编写的过程更轻松,以便有更多的时间花在业务的思考上,值得我们进一步探索。

最后,非常感谢大家的耐心阅读!因作者水平有限,难免有疏漏之处,请大家有任何疑问或建议,一定随时向作者反馈,以便我们能更好的改进,再次感谢!

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

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

相关文章

Python基于微博的大数据舆论,情感分析可视化系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

MATLAB --传统 GRAPPA MRI 重建

本文主要实现多通道脑部MRI图片的加速重建&#xff0c;使用GRAPPA方法。 目录 加载满采数据 数据欠采样 GRAPPA重建 完整数据代码下载 加载满采数据 load brain_8ch DATA DATA/max(max(max(abs(ifft2c(DATA))))) eps; 数据欠采样 maskones(sy,sx); for i1:2:syif 94…

ORACLE 如何使用dblink实现跨库访问

dbLink是简称&#xff0c;全称是databaselink。database link是定义一个数据库到另一个数据库的路径的对象&#xff0c;database link允许你查询远程表及执行远程程序。在任何分布式环境里&#xff0c;database都是必要的。另外要注意的是database link是单向的连接。在创建dat…

基于OpenCV的图形分析辨认02

目录 一、前言 二、实验目的 三、实验内容 四、实验过程 一、前言 编程语言&#xff1a;Python&#xff0c;编程软件&#xff1a;vscode或pycharm&#xff0c;必备的第三方库&#xff1a;OpenCV&#xff0c;numpy&#xff0c;matplotlib&#xff0c;os等等。 关于OpenCV&…

Python编程作业五:面向对象编程

目录 一、类的定义和方法 二、图书管理系统 一、类的定义和方法 定义一个学生类&#xff08;Student&#xff09;&#xff0c;包括学号(id)、姓名(name)、出生日期(birthday)和分数(score)4个属性&#xff0c;其中出生日期是私有属性&#xff0c;不能被外界直接访问。该类应具…

【论文阅读】Elucidating the Design Space of Diffusion-Based Generative Models

Elucidating the Design Space of Diffusion-Based Generative Models 引用&#xff1a; Karras T, Aittala M, Aila T, et al. Elucidating the design space of diffusion-based generative models[J]. Advances in Neural Information Processing Systems, 2022, 35: 26565…

打破界限,释放创新:一键将HTML转化为PDF

在互联网时代&#xff0c;HTML作为网页的标准语言&#xff0c;承载着无数的信息与创意。然而&#xff0c;有时我们需要将这些在线内容转化为可打印、可分享的PDF格式。这时&#xff0c;一款高效、便捷的转换工具就显得尤为重要。 首先&#xff0c;我们要进入首助编辑高手主页面…

智能边缘计算网关实现工业自动化与数据处理的融合-天拓四方

随着物联网&#xff08;IoT&#xff09;技术的迅速发展和普及&#xff0c;越来越多的设备被连接到互联网上&#xff0c;产生了海量的数据。如何有效地处理和分析这些数据&#xff0c;同时确保数据的安全性和实时性&#xff0c;成为了摆在企业面前的一大挑战。智能边缘计算网关作…

文心一言 VS 讯飞星火 VS chatgpt (209)-- 算法导论15.4 6题

六、设计一个 O(nlgn) 时间的算法&#xff0c;求一个 n 个数的序列的最长单调递增子序列。&#xff08;提示&#xff1a;注意到&#xff0c;一个长度为 i 的候选子序列的尾元素至少不比一个长度为 i-1 候选子序列的尾元素小。因此&#xff0c;可以在输入序列中将候选子序列链接…

8、JavaWeb-案例-部门管理-员工管理

P135 案例-准备工作 依据案例&#xff0c;学习根据接口文档开发接口的能力。 完成部门管理和员工管理两部分。可以分析这两部分&#xff0c;一个部门可以有多个员工&#xff0c;一个员工归属一个部门。 准备数据库表&#xff0c;创建一个springboot工程&#xff0c;引入web开…

第五十一回 李逵打死殷天赐 柴进失陷高唐州-AI发展历程和常用框架

朱仝说只要杀了李逵就上梁山&#xff0c;柴进就劝李逵先在庄上住一段时间&#xff0c;先让朱仝、雷横和吴用回了梁山。 李逵在柴进庄上住了一个月&#xff0c;碰到柴进的叔叔柴皇城病重来信叫他去一趟&#xff0c;于是李逵就随着柴进去了高唐州。 柴皇城被殷天锡气死&#xf…

微服务day05-Gateway网关

Gateway网关 为了防止微服务能被任何身份的人访问&#xff0c;需要对访问微服务的人做身份认证和权限校验。网关的功能就是对访问用户进行身份认证和权限校验。网关具有3种功能&#xff1a; 身份验证和权限校验&#xff1a;网关作为微服务入口&#xff0c;需要校验用户是是否…

自学高效备考2024年AMC10:2000-2023年1250道AMC10真题解析

我们今天继续来随机看5道AMC10真题&#xff0c;以及详细解析&#xff0c;这些题目来自1250道完整的官方历年AMC10真题库。通过系统研究和吃透AMC10的历年真题&#xff0c;参加AMC10的竞赛就能拿到好名次。 即使不参加AMC10竞赛&#xff0c;初中和高中数学一定会学得比较轻松、…

Java线程状态解析:多线程编程指南

&#x1f31f; 欢迎来到 我的博客&#xff01; &#x1f308; &#x1f4a1; 探索未知, 分享知识 !&#x1f4ab; 本文目录 &#x1f31f;1. 引言&#x1f31f;2. Java线程的生命周期&#x1f4a1;2.1 <font color "skyblue">新建&#xff08;New&#xff09;&…

去除PDF论文行号的完美解决方案

去除PDF论文行号的完美解决方案 1. 遇到的问题 我想去除论文的行号&#xff0c;但是使用网上的Adobe Acrobat裁剪保存后 如何去掉pdf的行编号&#xff1f; - 知乎 (zhihu.com) 翻译时依然会出现行号&#xff0c;或者是转成word&#xff0c;这样就大大损失了格式&#xff0c…

Python之Web开发初学者教程—ubuntu下vi的使用

Python之Web开发初学者教程—ubuntu下vi的使用 vi\vim 文本编辑器 i 切换到输入模式&#xff0c;以输入字符。 x 删除当前光标所在处的字符。 : 切换到底线命令模式&#xff0c;以在最底一行输入命令。 vi 保存并退出&#xff1a;esc键退出编辑-…

人工智能在信息系统安全中的运用

一、 概述 对于企业和消费者来讲&#xff0c;人工智能是非常有用的工具&#xff0c;那又该如何使用人工智能技术来保护敏感信息?通过快速处理数据并预测分析&#xff0c;AI可以完成从自动化系统到保护信息的所有工作。尽管有些黑客利用技术手段来达到自己的目的&#xff0c;但…

JAVA语言类与对象的关系

在Java语言中&#xff0c;类与对象是面向对象编程的核心概念&#xff0c;它们之间存在着紧密的关系。以下是关于Java语言中类与对象的关系的要点&#xff1a; 1. 类&#xff08;Class&#xff09;&#xff1a; 类是Java程序的基本构造块&#xff0c;它是一种用户自定义的数据…

OpenHarmony教程指南—Navigation开发 页面切换场景范例

简介 在应用开发时&#xff0c;我们常常遇到&#xff0c;需要在应用内多页面跳转场景时中使用Navigation导航组件做统一的页面跳转管理&#xff0c;它提供了一系列属性方法来设置页面的标题栏、工具栏以及菜单栏的各种展示样式。除此之外还拥有动态加载&#xff0c;navPathSta…

【信息系统项目管理师】--【信息技术发展】--【新一代信息技术及应用】--【虚拟现实】

文章目录 第二章 信息技术发展2.2 新一代信息技术及应用2.2.6 虚拟现实1.技术基础2.关键技术3.应用和发展 第二章 信息技术发展 信息技术是在信息科学的基本原理和方法下&#xff0c;获取信息、处理信息、传输信息和使用信息的应用技术总称。从信息技术的发展过程来看&#xff…