`
jackle_liu
  • 浏览: 149226 次
文章分类
社区版块
存档分类
最新评论

使用JMock来实现孤立测试(转)

阅读更多

使用JMock来实现孤立测试

 

我们在测试某类时,由于它要与其他类发生联系,因此往往在测试此类的代码中也将与之联系的类也一起测试了。这种测试,将使被测试的类直接依赖于其他类,一旦其他类发生改变,被测试类也随之被迫改变。更重要的是,这些其他类可能尚未经过测试,因此必须先测试这些类,才能测试被测试类。这种情况下,测试驱动开发成为空谈。而如果其他类中也引用了被测试类,我们到底先测试哪一个类?因此,在测试中,如果我们能将被测试类孤立起来,使其完全不依赖于其他类的具体实现,这样,我们就能做到测试先行,先测试哪个类,就先实现哪个类,而不管与之联系的类是否已经实现。

虚拟对象(mock object)就是为此需要而诞生的。它通过JDK中的反射机制,在运行时动态地创建虚拟对象。在测试代码中,我们可以验证这些虚拟对象是否被正确地调用了,也可以在明确的情况下,让其返回特定的假想值。而一旦有了这些虚拟对象提供的服务,被测试类就可以将虚拟对象作为其他与之联系的真实对象的替身,从而轻松地搭建起一个很完美的测试环境。

JMock是帮助创建mock对象的工具,它基于Java开发,在Java测试与开发环境中有不可比拟的优势,更重要的是,它大大简化了虚拟对象的使用。

本文中,通过一个简单的测试用例来说明JMock如何帮助我们实现这种孤立测试。有三个主要的类,User,UserDAO,及UserService。本文中,我们只需测试UserService,准备虚拟UserDAO。对于User,由于本身仅是一个过于简单的POJO,可以不用测试。但如果你是一个完美主义者,也可以使用JMock的虚拟它。在这领域,JMock几乎无所不能。:)

User是一个POJO,用以在视图中传输数据及映射数据库。其代码如下:

package com.sarkuya.model;

public class User {
    private String name;

    public User() {
    }
   
    public User(String name) {
        this.name = name;
    }
   
    public String getName() {
        return name;
    }
   
    public void setName(String name) {
        this.name = name;
    }
}


UserDAO负责与数据库打交道,通过数据库保存、获取User的信息。尽管我们可以不用知道JMock如何通过JDK的反射机制来实现孤立测试,但至少应知道,JDK的反射机制要求这些在运行时创建的动态类必须定义接口。在使用JMock的环境中,由于我们要虚拟UserDAO,意味着UserDAO必须定义接口。代码如下:

package com.sarkuya.dao;

import com.sarkuya.model.User;

public interface UserDAO {
    public void saveUser(User user);
    public User getUser(Long id);
}

UserService存有UserDAO的引用,通过其对外提供应用级的服务。相应地,我们先定义了其接口(尽管在本文中,作为被测试类,UserService不需要有接口,但如果以后此类需要被虚拟,也应该带有接口,基于此原因,我们也为其定义了接口)。

package com.sarkuya.service;

import com.sarkuya.dao.UserDAO;
import com.sarkuya.model.User;

public interface UserService {
    public void setUserDAO(UserDAO userDAO);
   
    public void saveUser(User user);
    public User getUser(Long id);
}

可以看到,除了setUserDAO()外,其另外的方法与UserDAO一样。这是设计模式中门面模式的典型应用,应用只通过UserService提供服务,而UserService在内部通过调用UserDAO来实现相应的功能。

根据测试先行的原则,你应该先写测试,再编写实现。这里先编写实现的原因,主要是使读者更加清楚我们接着要测试什么。由于本文是着重介绍JMock的使用,加上UserServiceImpl比较简单,因此先列出其代码如下:

package com.sarkuya.service.impl;

import com.sarkuya.dao.UserDAO;
import com.sarkuya.model.User;
import com.sarkuya.service.UserService;

public class UserServiceImpl implements UserService {
    private UserDAO userDAO;
   
    public UserServiceImpl() {
    }

    public void setUserDAO(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

    public User getUser(Long id) {
        return userDAO.getUser(id);
    }

    public void saveUser(User user) {
        userDAO.saveUser(user);
    }
}

下面是UserService的测试代码:

package com.sarkuya.service;

import com.sarkuya.dao.UserDAO;
import com.sarkuya.model.User;
import com.sarkuya.service.impl.UserServiceImpl;
import junit.framework.*;
import org.jmock.Mock;
import org.jmock.MockObjectTestCase;

public class UserServiceTest extends MockObjectTestCase {
    private UserService userService = new UserServiceImpl();
   
    private Mock userDAO = null;
   
    public UserServiceTest(String testName) {
        super(testName);
    }
   
    protected void setUp() throws Exception {
        userDAO = new Mock(UserDAO.class);
        userService.setUserDAO((UserDAO)userDAO.proxy());
    }
   
    protected void tearDown() throws Exception {
    }
   
    public static Test suite() {
        TestSuite suite = new TestSuite(UserServiceTest.class);
       
        return suite;
    }
   
    public void testGetUser() {
        User fakeUser = new User("John");
        userDAO.expects(once()).method("getUser").with(eq(1L)).will(returnValue(fakeUser));
       
        User user = userService.getUser(1L);
        assertNotNull(user);
        assertEquals("John", user.getName());
    }
   
    public void testSaveUser() {
        User fakeUser = new User("John");
       
        userDAO.expects(once()).method("getUser").with(eq(1L)).will(returnValue(fakeUser));
        User user = userService.getUser(1L);
        assertEquals("John", user.getName());
       
        userDAO.expects(once()).method("saveUser").with(same(fakeUser));
        user.setName("Mike");
        userService.saveUser(user);
       
        userDAO.expects(once()).method("getUser").with(eq(1L)).will(returnValue(user));
        User modifiedUser = userService.getUser(1L);
        assertEquals("Mike", user.getName());
    }
}

此段代码有几点应注意:

1、此测试类继承了JMock的MockObjectTestCase

2、private Mock userDAO = null;说明userDao是一个准备虚拟的对象

3、在setup()中,将userDAO.class传入Mock()后,再通过proxy()方法返回一个UserDAO的代理类实例(即虚拟对象实例),并赋值于userService

4、在testGetUser()方法中,如果我们先将第一行及第二行代码屏蔽掉,可以看出,这是一个真实环境下的测试代码。先获取一个User,然后确认其非空值,再确认其姓名为“John”。此时,在真实环境下,这段代码要测试成功的前提必须是UserDAO已经连接到了数据库,然后返回一个User后传给UserService。
但问题是,到目前为止,且不说UserDAO还未经历连接数据库这一系列繁琐而痛苦的过程,我们甚至还未实现UserDAO的接口!那么,为何加上第一行及第二行代码后就可以了呢?这正是JMock的威力所在。先实例化一个测试用的fakeUser,然后通过一系列的指令,在第二行代码中告诉JMock应该如何“做假”。尽管这句代码很长,我们可作如下理解:
1) userDAO.expects(once()):我们期望userDAO的某方法被执行一次,如果此方法未被执行,或者执行了二次以上,测试就不会通过
2) method("getUser"):这个期望被执行一次的方法名为userDAO.getUser()
3) with(eq(1L)):执行getUser()方法时,确认其传入的参数值为“1L”
4) will(returnValue(fakeUser)):上述条件均满足后,返回一个虚假的对象,即我们前面实例化的fakeUser
总体来说,当设定好第二行语句后,JMock就在后台监控着,确保userDAO.getUser()必须,且只被执行一次,且参数“1L”已经正确地传给了此方法,一旦这些条件被满足,就返回fakeUser。
而在第三行,User user = userService.getUser(1L)将触发所有这些条件,作为奖励,它接受了奖品fakeUser并赋值于user对象。而下面第四行及第五行均对此user对象进行测试,不通过才怪。

5) testSaveUser()方法中的原理类似。其思路是,将id为“1”的user从数据库中取出,将其名改为“Mike”,再存回数据库,然后再从数据库中取出此user,确保其名字已被改变。
第五行userDAO.expects(once()).method("saveUser").with(same(fakeUser))比较特殊。首先,with(same(fakeUser))说明,传入参数必须是fakeUser此实例,尽管我们在下面的语句中通过user.setName("Mike"),但只是改变了其name的属性,而fakeUser的实例引用并未发生改变,因此可以满足条件。其次,其后没有.will(returnValue(fakeUser)),因为userDAO.saveUser()不需要返回任何对象或基本数据类型。
另外,当再次执行userDAO.expects()时,JMock将重设其监控条件。我们也可以通过userDAO.reset()来显式是清除监控条件。

通过以上实例代码及其说明,我们看出,用好JMock的关键是先设置监控条件,再写相应的测试语句。一旦设好监控条件后,在某段代码块执行完毕时,如果监控条件未得到满足,或是没有通过expects()再次重设条件,或通过reset()来显式是清除监控条件,测试将无法通过。

以上介绍了JMock的基本使用方法。而这种基本用法,占了全面掌握JMock所需学习的知识70%以上。关于JMock的更多细节,感兴趣的读者可以访问JMock的网站进一步学习。

分享到:
评论

相关推荐

    jmock cookbook 资源整合

    JMock是一个用于Java应用程序单元测试的工具,它允许程序员模拟对象的行为,以便在孤立的环境中测试代码。在这个资源包中,包含了英文版的《JMock_CookBook_EN.pdf》和中文版的《JMock_CookBook_CN.pdf》,为不同...

    毕设单片机实战项目基于esp8266的高考倒计时.zip

    【项目资源】: 单片机项目适用于从基础到高级的各种项目,特别是在性能要求较高的场景中,比如操作系统开发、嵌入式编程和底层系统编程。如果您是初学者,可以从简单的控制台程序开始练习;如果是进阶开发者,可以尝试涉及硬件或网络的项目。 【项目质量】: 所有源码都经过严格测试,可以直接运行。 功能在确认正常工作后才上传。 【适用人群】: 适用于希望学习不同技术领域的小白或进阶学习者。 可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】: 项目具有较高的学习借鉴价值,也可直接拿来修改复刻。 对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同进步。 # 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。

    毕设工坊:专注于计算机毕业设计项目的交流与资源共享平台,涵盖各类技术文档、代码示例及实战经验分享,助力学子顺利完成学业挑战

    毕设工坊:专注于计算机毕业设计项目的交流与资源共享平台,涵盖各类技术文档、代码示例及实战经验分享,助力学子顺利完成学业挑战。

    【window 可视化nvm管理node版本 nvm-desktop】

    【window 可视化nvm管理node版本 nvm-desktop】

    《基于YOLOv8的玉器识别系统》(包含源码、完整数据集、可视化界面、部署教程)简单部署即可运行。功能完善、操作简单,适合毕设或课程设计.zip

    资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。

    (源码)基于microbit编程语言的mymicrobit扩展插件项目.zip

    # 基于microbit编程语言的mymicrobit扩展插件项目 ## 项目简介 这是一个基于microbit编程语言的mymicrobit扩展插件项目。该项目旨在提供额外的功能和特性,以扩展microbit编程环境。通过此插件,用户可以轻松地在MakeCode环境中进行编程,实现对micro:bit设备的更多控制和功能实现。 ## 项目的主要特性和功能 1. 扩展性提供了丰富的积木块和代码库,允许用户轻松实现复杂的编程逻辑和功能扩展。 2. 图形化编程支持通过积木块形式的图形化编程,降低编程门槛,方便初学者快速上手。 3. 实时预览提供了积木块的实时预览功能,方便用户直观地了解代码块的逻辑和功能。 4. 与MakeCode无缝集成可以直接在MakeCode环境中导入和使用,无需额外的配置和安装。 ## 安装使用步骤

    毕设单片机实战项目基于ESP8266的局域网图片刷新显示系统.zip

    【项目资源】: 单片机项目适用于从基础到高级的各种项目,特别是在性能要求较高的场景中,比如操作系统开发、嵌入式编程和底层系统编程。如果您是初学者,可以从简单的控制台程序开始练习;如果是进阶开发者,可以尝试涉及硬件或网络的项目。 【项目质量】: 所有源码都经过严格测试,可以直接运行。 功能在确认正常工作后才上传。 【适用人群】: 适用于希望学习不同技术领域的小白或进阶学习者。 可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】: 项目具有较高的学习借鉴价值,也可直接拿来修改复刻。 对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同进步。 # 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。

    《基于YOLOv8的印章分析系统》(包含源码、完整数据集、可视化界面、部署教程)简单部署即可运行。功能完善、操作简单,适合毕设或课程设计.zip

    资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。

    p111基于django的企业员工管理系统.zip

    项目资源包含:可运行源码+sql文件 适用人群:学习不同技术领域的小白或进阶学习者;可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 项目具有较高的学习借鉴价值,也可拿来修改、二次开发。 有任何使用上的问题,欢迎随时与博主沟通,博主看到后会第一时间及时解答。 开发语言:Python 框架:django Python版本:python3.8 数据库:mysql 5.7 数据库工具:Navicat 开发软件:PyCharm 浏览器:谷歌浏览器

    第三章-局域网-思维导图

    第三章-局域网-思维导图

    机械工程PT300机械故障仿真测试台:高校教学与科研用精密振动分析及故障诊断实验系统了您提供的规范

    内容概要:PT300机械故障综合模拟实验台由瓦仑尼安教学设备有限公司生产,旨在帮助用户深入了解振动特征知识及复杂转子振动频谱分析,实现精密振动分析和精准故障诊断。该实验台能模拟轴承故障、不平衡、不对中、设备松动、转子摩擦等多种机械故障现象,可进行不同转速下的轴承故障频率识别、转子静动平衡模拟试验、设备启停机测试等实验。设备采用高效节能ABB三相交流电动机,配备高精度转速控制和测量模块,确保运行稳定。此外,实验台还设有透明防震安全罩和互锁开关,保障实验安全。; 适合人群:高校师生、科研人员等需要学习或研究机械故障诊断相关理论知识和实践技能的人群。; 使用场景及目标:①用于高校等教育机构的教学,辅助学生理解机械故障诊断的理论知识和实践技能;②满足科研人员进行机械故障诊断算法验证、故障特征分析等科研需求。; 其他说明:PT300机械故障综合模拟实验台的每个部件均经过高精度加工,确保在不同振动状态下稳定运行。用户可根据期望分析特定部件的故障特征。设备尺寸为735mm(长)×310mm(宽)×350mm(高),保修一年,且提供免费操作指导服务。

    Android毕设实战项目基于Android+Django+sqlit3开发.zip

    【项目资源】: 适用于从基础到高级的各种项目,特别是在性能要求较高的场景中,比如操作系统开发、嵌入式编程和底层系统编程。如果您是初学者,可以从简单的控制台程序开始练习;如果是进阶开发者,可以尝试涉及硬件或网络的项目。 【项目质量】: 所有源码都经过严格测试,可以直接运行。 功能在确认正常工作后才上传。 【适用人群】: 适用于希望学习不同技术领域的小白或进阶学习者。 可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】: 项目具有较高的学习借鉴价值,也可直接拿来修改复刻。 对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同进步。 # 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。

    【光子晶体模拟】基于COMSOL弱形式PDE的三维光子晶体能带结构计算与优化:电磁场切向连续性处理及带隙分析系统设计使用COMSOL

    内容概要:本文详细介绍了使用COMSOL Multiphysics的弱形式接口对三维光子晶体进行数值模拟的方法和技巧。文章通过具体的代码示例,解释了如何构建光子晶体的介电常数分布、设置弱形式PDE、处理电磁场切向连续性、应用Floquet周期边界条件以及特征值求解等关键步骤。特别强调了弱形式接口相比传统物理场接口的优势,如灵活性和对复杂边界的处理能力。文中还分享了一些实用的经验和注意事项,如布洛赫边界条件的实现、特征值求解器参数的优化配置以及网格划分的技巧。 适合人群:具备一定电磁学和数值模拟基础的研究人员或工程师,尤其是对光子晶体仿真感兴趣的读者。 使用场景及目标:①理解并掌握COMSOL弱形式接口在光子晶体仿真中的应用;②学习如何通过弱形式设置处理复杂的电磁场问题;③提高对光子晶体能带结构和带隙特性的认识;④掌握特征值求解和网格划分的最佳实践。 阅读建议:由于本文涉及较多的具体代码和物理概念,建议读者在阅读过程中结合COMSOL软件进行实际操作,同时查阅相关电磁理论书籍以加深理解。此外,对于文中提到的一些具体参数设置和技巧,可以通过尝试不同的配置来巩固所学知识。

    (源码)基于Arduino平台的INSPTComputacion2项目.zip

    # 基于Arduino平台的INSPTComputacion2项目 ## 项目简介 INSPTComputacion2是一个基于Arduino平台的开发项目。该项目旨在通过Arduino的硬件和软件能力,实现一系列计算和交互功能。通过此项目,用户可以体验到Arduino在嵌入式系统、物联网和微控制器等领域的强大功能。 ## 项目的主要特性和功能 该项目的主要特性和功能包括但不限于以下几点 1. 嵌入式系统开发利用Arduino的硬件资源,开发嵌入式系统应用。 2. 物联网应用实现Arduino与物联网技术的结合,进行数据采集、传输和控制。 3. 交互设计通过Arduino实现人机交互,如按钮控制、LED显示等。 4. 数据处理利用Arduino进行数据处理和分析,如温度、湿度等环境数据的采集和处理。 ## 安装使用步骤 以下是在已下载本项目源码文件后的安装使用步骤 1. 确保已安装Arduino IDE软件。

    毕业设计物联网实战项目基于云且连接 Internet 的新式应用程序。 可用于建立Web应用、 IoT物联网、移动后端等。.zip

    【项目资源】: 物联网项目适用于从基础到高级的各种项目,特别是在性能要求较高的场景中,比如操作系统开发、嵌入式编程和底层系统编程。如果您是初学者,可以从简单的控制台程序开始练习;如果是进阶开发者,可以尝试涉及硬件或网络的项目。 【项目质量】: 所有源码都经过严格测试,可以直接运行。 功能在确认正常工作后才上传。 【适用人群】: 适用于希望学习不同技术领域的小白或进阶学习者。 可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】: 项目具有较高的学习借鉴价值,也可直接拿来修改复刻。 对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同进步。 # 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。

    毕业设计物联网实战项目基于touchgfx,调度基于freertos.zip

    【项目资源】: 物联网项目适用于从基础到高级的各种项目,特别是在性能要求较高的场景中,比如操作系统开发、嵌入式编程和底层系统编程。如果您是初学者,可以从简单的控制台程序开始练习;如果是进阶开发者,可以尝试涉及硬件或网络的项目。 【项目质量】: 所有源码都经过严格测试,可以直接运行。 功能在确认正常工作后才上传。 【适用人群】: 适用于希望学习不同技术领域的小白或进阶学习者。 可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】: 项目具有较高的学习借鉴价值,也可直接拿来修改复刻。 对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同进步。 # 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。

    Python数据结构-学习笔记

    Python数据结构-学习笔记

    电影在线购票系统(springboot+ssm+vue+mysql)含万字系统详细说明文档

    该系统展示了一个电影在线购票系统的结构图,系统分为前台和后台两部分。前台包括首页、影院信息、电影信息、电影资讯和个人中心等模块,主要面向普通用户,提供电影浏览、选座购票、个人账户管理等功能。后台部分由管理员通过后台模块进行操作,包括系统首页、用户管理、场次管理、时间段管理、影院信息管理、电影分类管理、电影信息管理、订单管理和个人中心等模块,用于系统的维护和管理,如用户信息维护、电影和影院信息更新、订单处理等。整个系统旨在为用户提供便捷的在线购票体验,同时确保后台管理的高效和有序。

    5G NR射频基本指标一致性自测用例

    5G NR射频一致性自测用例 由于NR射频测试场景太多,全指标自动化跑测用时太久,本表格选取了主要场景的关键指标,以便于射频工程师对产品的NR射频指标进行初步摸底。 表格每一页概况: 1、NR TDD摸底指标N77/78/79/41 2、NR FDD摸底指标N1/3//5/8/28 附录1、各频段带宽所支持的SCS 附录2、各带宽SCS的RB配置 附录3、灵敏度测试的RB配置 附录4、摸底测试信道查询 附录5、各频段频率范围

    毕业设计物联网实战项目基于STM32、ESP8266、EMQX和Android的智能家居系统.zip

    【项目资源】: 物联网项目适用于从基础到高级的各种项目,特别是在性能要求较高的场景中,比如操作系统开发、嵌入式编程和底层系统编程。如果您是初学者,可以从简单的控制台程序开始练习;如果是进阶开发者,可以尝试涉及硬件或网络的项目。 【项目质量】: 所有源码都经过严格测试,可以直接运行。 功能在确认正常工作后才上传。 【适用人群】: 适用于希望学习不同技术领域的小白或进阶学习者。 可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】: 项目具有较高的学习借鉴价值,也可直接拿来修改复刻。 对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同进步。 # 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。

Global site tag (gtag.js) - Google Analytics