`

单元测试系列之3:测试整合之王Unitils

阅读更多
引述:程序测试对保障应用程序正确性而言,其重要性怎么样强调都不为过。JUnit是必须事先掌握的测试框架,大多数测试框架和测试工具都在此基础上扩展而来,Spring对测试所提供的帮助类也是在JUnit的基础上进行演化的。直接使用JUnit测试基于Spring的应用存在诸多不便,不可避免地需要将大量的精力用于应付测试夹具准备、测试现场恢复、访问测试数据操作结果等边缘性的工作中。Mockito、Unitils、Dbunit等框架的出现,这些问题有了很好的解决方案,特别是Unitils结合Dbunit对测试DAO层提供了强大的支持,大大提高了编写测试用例的效率和质量。

   Unitils海纳百川(Junit,dbunit,mockito spring hibernate and so on..),以打造一个在实际应用开发中真正实战的测试框架,是致力于应用实战的开发者不得不学习的开源框架。

Unitils概述

   Unitils测试框架目的是让单元测试变得更加容易和可维护。Unitils构建在DbUnit与EasyMock项目之上并与JUnit和TestNG相结合。支持数据库测试,支持利用Mock对象进行测试并提供与Spring和Hibernate相集成。Unitils设计成以一种高度可配置和松散耦合的方式来添加这些服务到单元测试中,目前其最新版本是3.1。

Unitils功能特点

  •  自动维护和强制关闭单元测试数据库(支持Oracle、Hsqldb、MySQL、DB2)。
  •  简化单元测试数据库连接的设置。
  •  简化利用DbUnit测试数据的插入。
  •  简化Hibernate session管理。
  •  自动测试与数据库相映射的Hibernate映射对象。
  •  易于把Spring管理的Bean注入到单元测试中,支持在单元测试中使用Spring容器中的Hibernate SessionFactory。
  •  简化EasyMock Mock对象创建。
  •  简化Mock对象注入,利用反射等式匹配EasyMock参数。


Unitils模块组件

   Unitils通过模块化的方式来组织各个功能模块,采用类似于Spring的模块划分方式,如unitils-core、unitils-database、unitils-mock等。比以前整合在一个工程里面显得更加清晰,目前所有模块如下所示:
  •   unitils-core:核心内核包。
  •   unitils-database:维护测试数据库及连接池。
  •   unitils-DbUnit:使用DbUnit来管理测试数据。
  •   unitils-easymock:支持创建Mock和宽松的反射参数匹配。
  •   unitils-inject:支持在一个对象中注入另一个对象。
  •   unitils-mock:整合各种Mock,在Mock的使用语法上进行了简化。
  •   unitils-orm:支持Hibernate、JPA的配置和自动数据库映射检查。
  •   unitils-spring:支持加载Spring的上下文配置,并检索和Spring Bean注入。

   Unitils的核心架构中包含Moudule和TestListener两个概念,类似Spring中黏连其他开源软件中的FactoryBean概念。可以看成第三方测试工具的一个黏合剂。整体框架如图16-4所示:



   通过TestListener可以在测试运行的不同阶段注入某些功能。同时某一个TestListener又被一个对应的Module所持有。Unitils也可以看成一个插件体系结构,TestListener在整个Unitils中又充当了插件中扩展点的角色,从TestListener这个接口中我们可以看到,它可以在crateTestObject、before(after)Class、before(after)TestMethod、beforeSetup、afterTeardown的不同切入点添加不同的动作。

Unitils配置文件

  •   unitils-defaults.properties:默认配置文件,开启所有功能。
  •   unitils.properties:项目级配置文件,用于项目通用属性配置。
  •   unitils-local.properties:用户级配置文件,用于个人特殊属性配置。

    Unitils的配置定义了一般配置文件的名字unitils.properties和用户自定义配置文件unitils-local.properties,并给出了默认的模块及模块对应的className,便于Unitils加载对应的模块module。但是如果用户分别在unitils.properties文件及unitils -local.properties文件中对相同属性配置不同值时,将会以unitils-local.properties 的配置内容为主。

Unitils断言

   典型的单元测试一般都包含一个重要的组成部分:对比实际产生的结果和希望的结果是否一致的方法,即断言方法(assertEquals)。Unitils 为我们提供了一个非常实用的断言方法,我们以第2章中编写的用户领域对象User为蓝本,比较两个User对象的实例来开始认识Unitils的断言之旅。

assertReflectionEquals:反射断言

    在Java世界中,要比较现有两个对象实例是否相等,如果类没有重写equals()方法,用两个对象的引用是否一致作为判断依据。有时候,我们并不需要关注两个对象是否引用同一个对象,只要两个对象的属性值一样就可以了。在JUnit单元测试中,有两种测试方式进行这样的场景测试:一是在比较实体类中重写equals()方法,然后进行对象比较;二是把对象实例的属性一个一个进行比较。不管采用哪种方法,都比较烦锁,Unitils为我们提供了一种非常简单的方法,即使用ReflectionAssert.assertReflectionEquals方法, 如代码清单16-11所示:

package com.baobaotao.test;
import java.util.*;
import org.junit.Test;
import static org.unitils.reflectionassert.ReflectionAssert.*;
import static org.unitils.reflectionassert.ReflectionComparatorMode.*;
import com.baobaotao.domain.User;

public class AssertReflectionEqualsTest {
	@Test
	public void testReflection(){
		User user1 = new User("tom","1234");
		User user2 = new User("tom","1234");
		ReflectionAssert.assertReflectionEquals(user1, user2);
	}

}


    ReflectionAssert. AssertReflectionEquals(期望值,实际值,比较级别)方法为我们提供了各种级别的比较断言。下面我们依次介绍这些级别的比较断言。
    ReflectionComparatorMode.LENIENT_ORDER:忽略要断言集合collection 或者array 中元素的顺序。
    ReflectionComparatorMode.IGNORE_DEFAULTS:忽略Java类型默认值,如引用类型为null,整型类型为0,或者布尔类型为false时,那么断言忽略这些值的比较。
    ReflectionComparatorMode.LENIENT_DATES:比较两个实例的Date是不是都被设置了值或者都为null,而忽略Date的值是否相等。

assertLenientEquals:断言

   ReflectionAssert 类为我们提供了两种比较断言:既忽略顺序又忽略默认值的断言assertLenientEquals,使用这种断言就可以进行简单比较。下面通过实例学习其具体的用法,如代码清单16-12所示。
package com.baobaotao.test;
import java.util.*;
…
public class AssertReflectionEqualsTest {
	  Integer orderList1[] = new Integer[]{1,2,3};
	  Integer orderList2[] = new Integer[]{3,2,1};

	    
	    //① 测试两个数组的值是否相等,忽略顺序
	    //assertReflectionEquals(orderList1, orderList2,LENIENT_ORDER);
assertLenientEquals(orderList1, orderList2);

	    
	    //② 测试两个对象的值是否相等,忽略时间值是否相等
	    User user1 = new User("tom","1234");
	    Calendar cal1 = Calendar.getInstance();
	    user1.setLastVisit(cal1.getTime());
	    User user2 = new User("tom","1234");
	    Calendar cal2 = Calendar.getInstance();
	    cal2.set(Calendar.DATE, 15);
	    user2.setLastVisit(cal2.getTime());
//assertReflectionEquals(user1, user2,LENIENT_DATES);
	    assertLenientEquals(user1, user2);
}


assertPropertyXxxEquals:属性断言

   assertLenientEquals 和assertReflectionEquals 这两个方法是把对象作为整体进行比较,ReflectionAssert 类还给我们提供了只比较对象特定属性的方法:assertPropertyReflection   Equals()和assertPropertyLenientEquals()。下面通过实例学习其具体的用法,如代码清单16-13所示。

package com.baobaotao.test;
import java.util.*;
…
public class AssertReflectionEqualsTest {
	  User user = new User("tom","1234");
	  assertPropertyReflectionEquals("userName", "tom", user);
	  assertPropertyLenientEquals("lastVisit", null, user);
}

   assertPropertyReflectionEquals()断言是默认严格比较模式但是可以手动设置比较级别的断言,assertPropertyLenientEquals()断言是具有忽略顺序和忽略默认值的断言。


集成Spring

   Unitils 提供了一些在Spring 框架下进行单元测试的特性。Spring 的一个基本特性就是,类要设计成为没有Spring 容器或者在其他容器下仍然易于进行单元测试。但是很多时候在Spring 容器下进行测试还是非常有用的。
   Unitils 提供了以下支持 Spring 的特性:
  •   ApplicationContext 配置的管理;
  •  在单元测试代码中注入Spring 的Beans;
  •  使用定义在Spring 配置文件里的Hibernate SessionFactory;
  •  引用在Spring 配置中Unitils 数据源。


ApplicationContext 配置
   可以简单地在一个类、方法或者属性上加上@SpringApplicationContext 注解,并用Spring的配置文件作为参数,来加载Spring应用程序上下文。下面我们通过实例来介绍一下如何创建ApplicationContext。

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.unitils.UnitilsJUnit4;
import org.unitils.spring.annotation.SpringApplicationContext;
import org.unitils.spring.annotation.SpringBean;
import com.baobaotao.service.UserService;
import static org.junit.Assert.*;
//①用户服务测试
public class UserServiceTest extends UnitilsJUnit4 {

//①-1 加载Spring配置文件
	@SpringApplicationContext({"baobaotao-service.xml", "baobaotao-dao.xml"})
	private ApplicationContext applicationContext;

//①-1 加载Spring容器中的Bean
	@SpringBean("userService")
	private UserService userService;
	
//①-3 测试Spring容器中的用户服务Bean
@Test
	public void testUserService (){
		assertNotNull(applicationContext);
		assertNotNull(userService.findUserByUserName("tom"));
	}
}
…


   在①-1处,通过@SpringApplicationContext 注解加载baobaotao-service.xml和baobaotao- dao.xml两个配置文件,生成一个Spring应用上下文,我们就可以在注解的范围内引用applicationContext这个上下文。在①-2处,通过@SpringBean注解注入当前Spring容器中相应的Bean,如实例中加载ID为“userService”的Bean到当前测试范围。在①-3处,通过JUnit断言验证是否成功加载applicationContext和userService。Unitils加载Spring上下文的过程是:首先扫描父类的@SpringApplicationContext注解,如果找到了就在加载子类的配置文件之前加载父类的配置文件,这样就可以让子类重写配置文件和加载特定配置文件。
   细心的读者可能会发现,采用这种方式加载Spring应用上下文,每次执行测试时,都会重复加载Spring应用上下文。Unitils为我们提供在类上加载Spring应用上下文的能力,以避免重复加载的问题。

…
@SpringApplicationContext({"baobaotao-service.xml", "baobaotao-dao.xml"})
public class BaseServiceTest extends UnitilsJUnit4 {
    
 //加载Spring上下文
	@SpringApplicationContext
	public ApplicationContext applicationContext;

}

  
   在父类BaseServiceTest里指定了Spring配置文件,Spring应用上下文只会创建一次,然后在子类SimpleUserServiceTest 里会重用这个应用程序上下文。加载Spring应用上下文是一个非常繁重的操作,如果重用这个Spring应用上下文就会大大提升测试的性能。
…
public class SimpleUserServiceTest extends BaseServiceTest {
	
//① Spring容器中加载Id为"userService"的Bean
	@SpringBean("userService")
	private UserService userService1;

//② 从Spring容器中加载与UserService相同类型的Bean
	@SpringBeanByType
	private UserService userService2;

	//③ 从Spring容器中加载与userService相同名称的Bean
	@SpringBeanByName
	private  UserService userService;
	
     //④ 使用父类的Spring上下文
	@Test
	public void testApplicationContext(){
		assertNotNull(applicationContext);
	}
	
	@Test
	public void testUserService(){
		assertNotNull(userService.findUserByUserName("tom"));
		assertNotNull(userService1.findUserByUserName("tom"));
		assertNotNull(userService2.findUserByUserName("tom"));
	}
}
…


   在①处,使用@SpringBean 注解从Spring容器中加载一个ID为userService的Bean。在②处,使用@ SpringBeanByType注解从Spring容器中加载一个与UserService相同类型的Bean,如果找不到相同类型的Bean,就会抛出异常。在③处,使用@SpringBeanByName 注解从Spring容器中加载一个与当前属性名称相同的Bean。

集成Hibernate

   Hibernate是一个优秀的O / R开源框架,它极大地简化了应用程序的数据访问层开发。虽然我们在使用一个优秀的O/R框架,但并不意味我们无须对数据访问层进行单元测试。单元测试仍然非常重要。它不仅可以确保Hibernate映射类的映射正确性,也可以很便捷地测试HQL查询等语句。Unitils为方便测试 Hibernate,提供了许多实用的工具类,如HibernateUnitils就是其中一个,使用assertMappingWithDatabaseConsistent()方法,就可以方便测试映射文件的正确性。

SessionFactory 配置

   可以简单地在一个类、方法或者属性上加上@ HibernateSessionFactory 注解,并用Hibernate的配置文件作为参数,来加载Hibernate上下文。下面我们通过实例来介绍一下如何创建SessionFactory。

…
@HibernateSessionFactory("hibernate.cfg.xml")
public class BaseDaoTest extends UnitilsJUnit4 {
	@HibernateSessionFactory
	public SessionFactory sessionFactory;
	

	@Test
	public void testSessionFactory(){
		assertNotNull(sessionFactory);
	}
}


    在父类BaseDaoTest里指定了Hibernate配置文件,Hibernate应用上下文只会创建一次,然后在子类SimpleUserDaoTest里会重用这个应用程序上下文。加载Hibernate应用上下文是一个非常繁重的操作,如果重用这个Hibernate应用上下文就会大大提升测试的性能。

…
public class SimpleUserDaoTest extends BaseDaoTest {
	private UserDao userDao;

//① 初始化UserDao
@Before
	public void init(){
	     userDao = new WithoutSpringUserDaoImpl();
		userDao.setSessionFactory(sessionFactory); //使用父类的SessionFactory
	}

//② Hibernate映射测试
@Test
    public void testMappingToDatabase() {
        HibernateUnitils.assertMappingWithDatabaseConsistent();
}

//③ 测试UserDao
	@Test
	public void testUserDao(){
		assertNotNull(userDao);
		assertNotNull(userDao.findUserByUserName("tom"));
		assertEquals("tom", userDao.findUserByUserName("tom").getUserName());
	}
}
…


   为了更好演示如何应用Unitils测试基于Hibernate数据访问层,在这个实例中不使用Spring框架。所以在执行测试时,需要先创建相应的数据访问层实例,如实例中的userDao。其创建过程如①处所示,先手工实例化一个UserDao,然后获取父类中创建的SessionFactory,并设置到UserDao中。在②处,使用Unitils提供的工具类HibernateUnitils中的方法测试我们的Hibernate映射文件。在③处,通过JUnit的断言验证 UserDao相关方法,看是否与我们预期的结果一致。

集成Dbunit
   
   Dbunit是一个基于JUnit扩展的数据库测试框架。它提供了大量的类,对数据库相关的操作进行了抽象和封装。Dbunit通过使用用户自定义的数据集以及相关操作使数据库处于一种可知的状态,从而使得测试自动化、可重复和相对独立。虽然不用Dbunit也可以达到这种目的,但是我们必须为此付出代价(编写大量代码、测试及维护)。既然有了这么优秀的开源框架,我们又何必再造轮子。目前其最新的版本是2.4.8。
    随着Unitils的出现,将Spring、Hibernate、DbUnit等整合在一起,使得DAO层的单元测试变得非常容易。Unitils采用模块化方式来整合第三方框架,通过实现扩展模块接口org.unitils.core.Module来实现扩展功能。在Unitils中已经实现一个DbUnitModule,很好整合了DbUnit。通过这个扩展模块,就可以在Unitils中使用Dbunit强大的数据集功能,如用于准备数据的@DataSet注解、用于验证数据的@ExpectedDataSet注解。Unitils集成DbUnit流程图如图16-5所示。



16.4.5  自定义扩展模块

   Unitils通过模块化的方式来组织各个功能模块,对外提供一个统一的扩展模块接口org.unitils.core.Module来实现与第三方框架的集成及自定义扩展。在Unitils中已经实现目前一些主流框架的模块扩展,如Spring、Hibernate、DbUnit、Testng等。如果这些内置的扩展模块无法满足需求,我们可以实现自己的一些扩展模块。扩展Unitils模块很简单,如代码清单16-19所示。

package sample.unitils.module;
import java.lang.reflect.Method;
import org.unitils.core.TestListener;
import org.unitils.core. Module;
//① 实现Module接口
public class CustomExtModule implements Module {
     //② 实现获取测试监听的方法
	public TestListener getTestListener() {
		return new CustomExtListener();
	}
	
	//② 新建监听模块 
	protected class CustomExtListener extends TestListener {
         //③ 重写 TestListener里的相关方法,完成相关扩展的功能
		@Override
		public void afterTestMethod(Object testObject, Method testMethod,
				Throwable testThrowable) {
…
		}

		@Override
		public void beforeTestMethod(Object testObject, Method testMethod) {
…
		}
	}
…
}

在①处新建自定义扩展模块CustomExtModule,实现Module接口。在②处新建自定义监听模块,继承TestListener。在③处重写(@Override)TestListener里的相关方法,完成相关扩展的功能。实现自定义扩展模块之后,剩下的工作就是在Unitils配置文件unitils.properties中注册这个自定义扩展的模块:
引用
unitils.modules=…,custom
unitils.module. custom.className= sample.unitils.module.CustomExtModule


   这些文章摘自于我的《Spring 4.x企业应用开发实战》的第16章,我将通过连载的方式,陆续在此发出。欢迎大家讨论。
  • 大小: 26.2 KB
  • 大小: 25 KB
4
0
分享到:
评论
2 楼 renlongnian 2018-06-06  
//assertReflectionEquals(user1, user2,LENIENT_DATES); 
这句是忽略时间,仅验证时间是否有初始值。
没做验证,个人理解)


感谢楼主分享
1 楼 mojunbin 2012-05-08  
assertLenientEquals:断言
        ReflectionAssert 类为我们提供了两种比较断言:既忽略顺序又忽略默认值的断言assertLenientEquals,使用这种断言就可以进行简单比较。

package com.baobaotao.test;
import java.util.*;
…
public class AssertReflectionEqualsTest {
	  Integer orderList1[] = new Integer[]{1,2,3};
	  Integer orderList2[] = new Integer[]{3,2,1};

	    
	    //① 测试两个数组的值是否相等,忽略顺序
	    //assertReflectionEquals(orderList1, orderList2,LENIENT_ORDER);
assertLenientEquals(orderList1, orderList2);

	    
	    //② 测试两个对象的值是否相等,忽略时间值是否相等
	    User user1 = new User("tom","1234");
	    Calendar cal1 = Calendar.getInstance();
	    user1.setLastVisit(cal1.getTime());
	    User user2 = new User("tom","1234");
	    Calendar cal2 = Calendar.getInstance();
	    cal2.set(Calendar.DATE, 15);
	    user2.setLastVisit(cal2.getTime());
//assertReflectionEquals(user1, user2,LENIENT_DATES);
	    [color=red]assertLenientEquals(user1, user2);][/color]
}




上面这里貌似说得不对.代码中红色位置测试输出:false.
但是按照博主的注释//② 测试两个对象的值是否相等,忽略时间值是否相等但是ReflectionAssert .assertLenientEquals(user1,user2).应该是忽略顺序和默认值.
因此,我觉得这个demo有点歧义,呵呵.如果说错了,请见谅.

相关推荐

    node-v12.20.1-sunos-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    基于Springboot+Vue的乡政府管理系统-毕业源码案例设计.zip

    网络技术和计算机技术发展至今,已经拥有了深厚的理论基础,并在现实中进行了充分运用,尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代,所以对于信息的宣传和管理就很关键。系统化是必要的,设计网上系统不仅会节约人力和管理成本,还会安全保存庞大的数据量,对于信息的维护和检索也不需要花费很多时间,非常的便利。 网上系统是在MySQL中建立数据表保存信息,运用SpringBoot框架和Java语言编写。并按照软件设计开发流程进行设计实现。系统具备友好性且功能完善。 网上系统在让售信息规范化的同时,也能及时通过数据输入的有效性规则检测出错误数据,让数据的录入达到准确性的目的,进而提升数据的可靠性,让系统数据的错误率降至最低。 关键词:vue;MySQL;SpringBoot框架 【引流】 Java、Python、Node.js、Spring Boot、Django、Express、MySQL、PostgreSQL、MongoDB、React、Angular、Vue、Bootstrap、Material-UI、Redis、Docker、Kubernetes

    一名合格的程序猿修炼手册.md

    一名合格的程序猿修炼手册.

    5MHz 函数发生器使用说明书

    5MHz 函数发生器使用说明书

    99- 矿山工业互联网平台解决方案.pptx

    99- 矿山工业互联网平台解决方案.pptx

    基于Python大学生社会实践申报系统的设计与实现带vue前后端分离毕业源码案例设计.zip

    网络技术和计算机技术发展至今,已经拥有了深厚的理论基础,并在现实中进行了充分运用,尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代,所以对于信息的宣传和管理就很关键。系统化是必要的,设计网上系统不仅会节约人力和管理成本,还会安全保存庞大的数据量,对于信息的维护和检索也不需要花费很多时间,非常的便利。 网上系统是在MySQL中建立数据表保存信息,运用SpringBoot框架和Java语言编写。并按照软件设计开发流程进行设计实现。系统具备友好性且功能完善。 网上系统在让售信息规范化的同时,也能及时通过数据输入的有效性规则检测出错误数据,让数据的录入达到准确性的目的,进而提升数据的可靠性,让系统数据的错误率降至最低。 关键词:vue;MySQL;SpringBoot框架 【引流】 Java、Python、Node.js、Spring Boot、Django、Express、MySQL、PostgreSQL、MongoDB、React、Angular、Vue、Bootstrap、Material-UI、Redis、Docker、Kubernetes

    工厂工资明细表Excel模版

    基于提供的字段介绍,我们可以设计一个基础的工厂工资明细表Excel模板结构如下: | 序号 | 姓名 | 工种 | 工作天数 | 工时费/天 | 小计(正常工资) | 加班时间 | 加班费率/小时 | 小计(加班工资) | 预借 | 合计(实发工资) | 签字 | 备注 | | ---- | ---- | ---- | -------- | ---------- | -------------- | -------- | -------------- | --------------- | ---- | -------------- | ---- | ---- | | 1 | | | | | | | | | | | | | | 2 | | | | | =D2*C2

    供应链管理 高成本、高库存、重资产的解决方案.rar

    随着市场竞争的不断加剧和客户需求的多样化,传统的供应链管理模式面临着高成本、高库存和重资产等一系列挑战。为了有效应对这些挑战,企业亟需通过数字化转型来重塑供应链管理,实现效率提升和成本降低。本资料《供应链管理:高成本、高库存、重资产的解决方案》提供了针对这些问题的综合性数字化解决方案。在这份精品资料中,读者将了解到如何利用先进的信息技术手段,如大数据、云计算、物联网(IoT)和人工智能(AI),对供应链进行优化。通过实时数据分析,企业能够精准预测市场需求,从而减少过剩库存,降低仓储成本。同时,智能化的供应链协同平台可以加强供应商与制造商之间的合作,提高响应速度和灵活性,缩短产品交付周期。此外,资料还深入探讨了如何通过数字技术实现供应链的可视化管理,使企业能够全面掌握供应链的每一个环节,及时发现并解决问题,避免成本浪费。通过采用轻资产运营模式,企业能够减轻固定资产负担,提高资本使用效率。最终,这份资料不仅为企业提供了一套完整的供应链数字化转型路径,还结合具体案例分析,展示了数字化转型如何在实际操作中带来显著成效,帮助企业在激烈的市场竞争中保持领先地位。重新回答||

    五相感应电机矢量控制模型MATLAB

    适合相关科研人员,新手借鉴啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊

    node-v10.14.0-x64.msi

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    基于STM32F103C8单片机-FLASH读写程序KEIL工程源码.zip

    STM32学习软件编程资料,STM32F103C8单片机经典外设应用设计实例软件源代码,KEIL工程文件,可供学习参考。

    node-v12.22.8-sunos-x64.tar_3.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    node-v12.16.2-sunos-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    菜鸟自制流密码.docx

    菜鸟自制流密码.docx

    基于大数据的房产估价.doc

    基于大数据的房产估价 基于大数据的房产估价是一种利用海量数据和分析技术来评估房地产价值的方法。它通过收集、整合和分析各种与房地产相关的数据,以提供更加准确、全面的房产估价服务。 首先,大数据在房产估价中的应用主要体现在数据收集和处理上。这些数据可能包括不同时间点的房产属性、成交量、成交额、成交时长等,以及消费者线上行为数据和市场交易数据等。这些数据可以来自于多个渠道,如政府部门、房地产机构、互联网平台等。通过对这些数据的收集、清洗、整合和分析,可以更加准确地判断房地产市场的现状和趋势,为房产估价提供有力的数据支持。 其次,基于大数据的房产估价方法还可以结合地理信息系统(GIS)和其他技术工具,对房地产价格进行精细化分析。例如,可以利用GIS系统判断各类城市生活配套设施对房地产价格影响的权重,或者结合消费者行为数据和交易数据,分析目标消费者的核心需求和迫切程度,从而更准确地判断房地产项目的可行性和市场潜力。 此外,基于大数据的房产估价还可以利用机器学习、人工智能等先进技术,构建预测模型,对房地产市场的未来发展进行预测和研判。这些模型可以根据历史数据和趋势,分析各种因素对房地产价格的

    node-v11.6.0-linux-armv7l.tar.gz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    5G网优认证练习题题库.xlsx

    5G通信、网络优化与通信建设

    绘画学习平台微信小程序设计+ssm后端毕业源码案例设计.zip

    网络技术和计算机技术发展至今,已经拥有了深厚的理论基础,并在现实中进行了充分运用,尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代,所以对于信息的宣传和管理就很关键。系统化是必要的,设计网上系统不仅会节约人力和管理成本,还会安全保存庞大的数据量,对于信息的维护和检索也不需要花费很多时间,非常的便利。 网上系统是在MySQL中建立数据表保存信息,运用SpringBoot框架和Java语言编写。并按照软件设计开发流程进行设计实现。系统具备友好性且功能完善。 网上系统在让售信息规范化的同时,也能及时通过数据输入的有效性规则检测出错误数据,让数据的录入达到准确性的目的,进而提升数据的可靠性,让系统数据的错误率降至最低。 关键词:vue;MySQL;SpringBoot框架 【引流】 Java、Python、Node.js、Spring Boot、Django、Express、MySQL、PostgreSQL、MongoDB、React、Angular、Vue、Bootstrap、Material-UI、Redis、Docker、Kubernetes

    抛光机-零件图-机械工程图-机械三维3D建模图打包下载.zip

    抛光机_零件图_机械工程图_机械三维3D建模图打包下载.zip

    Cambro 2020 21 产品目录

    Cambro 2020 21 产品目录

Global site tag (gtag.js) - Google Analytics