c++返回指针时候注意提防_编写干净的测试–提防魔术

c++返回指针时候注意提防

很难为干净的代码找到一个好的定义,因为我们每个人都有自己的单词clean的定义。 但是,有一个似乎是通用的定义:

简洁的代码易于阅读。

这可能会让您感到有些惊讶,但我认为该定义也适用于测试代码。 使测试尽可能具有可读性是我们的最大利益,因为:

  • 如果我们的测试易于阅读,那么很容易理解我们的代码是如何工作的。
  • 如果我们的测试易于阅读,那么如果测试失败(不使用调试器),很容易发现问题。

编写干净的测试并不难,但是需要大量的实践,这就是为什么如此多的开发人员为此苦苦挣扎的原因。

我也为此感到挣扎,这就是为什么我决定与您分享我的发现的原因。

这是本教程的第三部分,介绍了如何编写干净的测试。 这次,我们将学习两种可用于从测试中删除幻数的技术。

救援常量

我们使用在我们的代码常量,因为没有常量我们的代码将与被散落幻数 。 使用幻数有两个结果:

  1. 我们的代码很难阅读,因为幻数只是没有意义的值。
  2. 我们的代码很难维护,因为如果必须更改幻数的值,则必须查找该幻数的所有出现并更新每个幻数。

换一种说法,

  • 常数帮助我们用描述其存在原因的某种事物代替幻数。
  • 常量使我们的代码更易于维护,因为如果常量的值发生变化,我们只需将该更改仅保留到一个位置即可。

如果我们考虑从测试案例中找到的幻数,我们会注意到它们可以分为两组:

  1. 与单个测试类相关的幻数。 这种幻数的典型示例是在测试方法中创建的对象的属性值。 我们应该在测试类中声明这些常量
  2. 与多个测试类别相关的幻数。 这种魔术数字的一个很好的例子是由Spring MVC控制器处理的请求的内容类型。 我们应该将这些常量添加到非实例化类中

让我们仔细看看这两种情况。

在测试类中声明常量

那么,为什么我们要在测试类中声明一些常量呢?

毕竟,如果我们考虑使用常量的好处,首先想到的是,我们应该通过创建包含测试中使用的常量的类来消除测试中的幻数。 例如,我们可以创建一个TodoConstants类,其中包含TodoControllerTestTodoCrudServiceTestTodoTest类中使用的常量。

这是一个坏主意

尽管有时候以这种方式共享数据是明智的,但是我们不应该轻易做出这个决定,因为在大多数情况下,我们在测试中引入常数的唯一动机是避免输入错误和幻数。

另外,如果幻数仅与单个测试类相关,则将这种依赖关系引入我们的测试是没有道理的,只是因为我们要最大程度地减少创建的常量的数量。

我认为,处理这种情况的最简单方法是在测试类中声明常量。

让我们找出如何改进本教程前面部分中描述的单元测试。 编写该单元测试以测试RepositoryUserService类的registerNewUserAccount()方法,并且当使用社交符号提供者和唯一的电子邮件地址创建新的用户帐户时,它验证此方法是否正常工作。

该测试用例的源代码如下所示:

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.security.crypto.password.PasswordEncoder;import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;@RunWith(MockitoJUnitRunner.class)
public class RepositoryUserServiceTest {private RepositoryUserService registrationService;@Mockprivate PasswordEncoder passwordEncoder;@Mockprivate UserRepository repository;@Beforepublic void setUp() {registrationService = new RepositoryUserService(passwordEncoder, repository);}@Testpublic void registerNewUserAccount_SocialSignInAndUniqueEmail_ShouldCreateNewUserAccountAndSetSignInProvider() throws DuplicateEmailException       {RegistrationForm registration = new RegistrationForm();registration.setEmail("john.smith@gmail.com");registration.setFirstName("John");registration.setLastName("Smith");registration.setSignInProvider(SocialMediaService.TWITTER);when(repository.findByEmail("john.smith@gmail.com")).thenReturn(null);when(repository.save(isA(User.class))).thenAnswer(new Answer<User>() {@Overridepublic User answer(InvocationOnMock invocation) throws Throwable {Object[] arguments = invocation.getArguments();return (User) arguments[0];}});User createdUserAccount = registrationService.registerNewUserAccount(registration);assertEquals("john.smith@gmail.com", createdUserAccount.getEmail());assertEquals("John", createdUserAccount.getFirstName());assertEquals("Smith", createdUserAccount.getLastName());assertEquals(SocialMediaService.TWITTER, createdUserAccount.getSignInProvider());assertEquals(Role.ROLE_USER, createdUserAccount.getRole());assertNull(createdUserAccount.getPassword());verify(repository, times(1)).findByEmail("john.smith@gmail.com");verify(repository, times(1)).save(createdUserAccount);verifyNoMoreInteractions(repository);verifyZeroInteractions(passwordEncoder);}
}

问题在于,此测试用例在创建新的RegistrationForm对象,配置UserRepository模拟的行为,验证返回的User对象的信息是否正确以及验证是否调用了UserRepository模拟的正确方法时使用了幻数。在经过测试的服务方法中。

通过在测试类中声明常量来删除这些幻数之后,测试的源代码如下所示:

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.security.crypto.password.PasswordEncoder;import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;@RunWith(MockitoJUnitRunner.class)
public class RepositoryUserServiceTest {private static final String REGISTRATION_EMAIL_ADDRESS = "john.smith@gmail.com";private static final String REGISTRATION_FIRST_NAME = "John";private static final String REGISTRATION_LAST_NAME = "Smith";private static final Role ROLE_REGISTERED_USER = Role.ROLE_USER;private static final SocialMediaService SOCIAL_SIGN_IN_PROVIDER = SocialMediaService.TWITTER;private RepositoryUserService registrationService;@Mockprivate PasswordEncoder passwordEncoder;@Mockprivate UserRepository repository;@Beforepublic void setUp() {registrationService = new RepositoryUserService(passwordEncoder, repository);}@Testpublic void registerNewUserAccount_SocialSignInAndUniqueEmail_ShouldCreateNewUserAccountAndSetSignInProvider() throws DuplicateEmailException       {RegistrationForm registration = new RegistrationForm();registration.setEmail(REGISTRATION_EMAIL_ADDRESS);registration.setFirstName(REGISTRATION_FIRST_NAME);registration.setLastName(REGISTRATION_LAST_NAME);registration.setSignInProvider(SOCIAL_SIGN_IN_PROVIDER);when(repository.findByEmail(REGISTRATION_EMAIL_ADDRESS)).thenReturn(null);when(repository.save(isA(User.class))).thenAnswer(new Answer<User>() {@Overridepublic User answer(InvocationOnMock invocation) throws Throwable {Object[] arguments = invocation.getArguments();return (User) arguments[0];}});User createdUserAccount = registrationService.registerNewUserAccount(registration);assertEquals(REGISTRATION_EMAIL_ADDRESS, createdUserAccount.getEmail());assertEquals(REGISTRATION_FIRST_NAME, createdUserAccount.getFirstName());assertEquals(REGISTRATION_LAST_NAME, createdUserAccount.getLastName());assertEquals(SOCIAL_SIGN_IN_PROVIDER, createdUserAccount.getSignInProvider());assertEquals(ROLE_REGISTERED_USER, createdUserAccount.getRole());assertNull(createdUserAccount.getPassword());verify(repository, times(1)).findByEmail(REGISTRATION_EMAIL_ADDRESS);verify(repository, times(1)).save(createdUserAccount);verifyNoMoreInteractions(repository);verifyZeroInteractions(passwordEncoder);}
}

此示例说明在测试类中声明常量具有三个好处:

  1. 我们的测试用例更易于阅读,因为魔术数字被正确命名的常量所替代。
  2. 我们的测试用例更易于维护,因为我们可以更改常量的值而无需对实际测试用例进行任何更改。
  3. RepositoryUserService类的registerNewUserAccount()方法编写新测试更加容易,因为我们可以使用常量而不是幻数。 这意味着我们不必担心拼写错误。

但是,有时我们的测试使用的幻数确实与多个测试类别相关。 让我们找出如何应对这种情况。

将常量添加到非实例性类

如果该常量与多个测试类相关,则在使用该常量的每个测试类中声明该常量是没有意义的。 让我们看一下一种情况,在这种情况下可以向非实例化类添加常量。

假设我们必须为REST API编写两个单元测试:

  • 第一个单元测试确保我们不能向数据库添加空的待办事项。
  • 第二个单元测试确保我们不能向数据库添加空笔记。

这些单元测试使用Spring MVC测试框架。 如果您不熟悉它,则可能要看一看我的
Spring MVC测试教程 。

第一个单元测试的源代码如下所示:

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;import java.nio.charset.Charset;import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {WebUnitTestContext.class})
@WebAppConfiguration
public class TodoControllerTest {private static final MediaType APPLICATION_JSON_UTF8 = new MediaType(MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(),Charset.forName("utf8"));private MockMvc mockMvc;@Autowiredprivate ObjectMapper objectMapper;@Autowiredprivate WebApplicationContext webAppContext;@Beforepublic void setUp() {mockMvc = MockMvcBuilders.webAppContextSetup(webAppContext).build();}@Testpublic void add_EmptyTodoEntry_ShouldReturnHttpRequestStatusBadRequest() throws Exception {TodoDTO addedTodoEntry = new TodoDTO();mockMvc.perform(post("/api/todo").contentType(APPLICATION_JSON_UTF8).content(objectMapper.writeValueAsBytes(addedTodoEntry))).andExpect(status().isBadRequest());}
}

第二个单元测试的源代码如下所示:

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;import java.nio.charset.Charset;import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {WebUnitTestContext.class})
@WebAppConfiguration
public class NoteControllerTest {private static final MediaType APPLICATION_JSON_UTF8 = new MediaType(MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(),Charset.forName("utf8"));private MockMvc mockMvc;@Autowiredprivate ObjectMapper objectMapper;@Autowiredprivate WebApplicationContext webAppContext;@Beforepublic void setUp() {mockMvc = MockMvcBuilders.webAppContextSetup(webAppContext).build();}@Testpublic void add_EmptyNote_ShouldReturnHttpRequestStatusBadRequest() throws Exception {NoteDTO addedNote = new NoteDTO();mockMvc.perform(post("/api/note").contentType(APPLICATION_JSON_UTF8).content(objectMapper.writeValueAsBytes(addedNote))).andExpect(status().isBadRequest());}
}

这两个测试类都声明一个名为APPLICATION_JSON_UTF8的常量。 该常数指定请求的内容类型和字符集。 同样,很明显,在每个测试类中都需要此常量,其中包含用于控制器方法的测试。

这是否意味着我们应该在每个这样的测试类中声明此常量?

没有!

由于以下两个原因,我们应将此常量移至非实例化类:

  1. 它与多个测试类别相关。
  2. 将其移到一个单独的类中可使我们更轻松地为控制器方法编写新测试并维护现有测试。

让我们创建一个最终的WebTestConstants类,将APPLICATION_JSON_UTF8常量移动到该类,然后向创建的类添加一个私有构造函数。

WebTestConstant类的源代码如下所示:

import org.springframework.http.MediaType;public final class WebTestConstants {public static final MediaType APPLICATION_JSON_UTF8 = new MediaType(MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(),Charset.forName("utf8"));private WebTestConstants() {}
}

完成此操作后,我们可以从测试类中删除APPLICATION_JSON_UTF8常量。 我们的新测试的源代码如下所示:

import com.fasterxml.jackson.databind.ObjectMapper;
import net.petrikainulainen.spring.jooq.config.WebUnitTestContext;
import net.petrikainulainen.spring.jooq.todo.dto.TodoDTO;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;import java.nio.charset.Charset;import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {WebUnitTestContext.class})
@WebAppConfiguration
public class TodoControllerTest {private MockMvc mockMvc;@Autowiredprivate ObjectMapper objectMapper;@Autowiredprivate WebApplicationContext webAppContext;@Beforepublic void setUp() {mockMvc = MockMvcBuilders.webAppContextSetup(webAppContext).build();}@Testpublic void add_EmptyTodoEntry_ShouldReturnHttpRequestStatusBadRequest() throws Exception {TodoDTO addedTodoEntry = new TodoDTO();mockMvc.perform(post("/api/todo").contentType(WebTestConstants.APPLICATION_JSON_UTF8).content(objectMapper.writeValueAsBytes(addedTodoEntry))).andExpect(status().isBadRequest());}
}

我们刚刚从测试类中删除了重复的代码,并减少了为控制器编写新测试所需的工作。 太酷了吧?

如果我们更改添加到常量类的常量的值,则此更改将影响使用该常量的每个测试用例。 这就是为什么我们应该最小化添加到常量类的常量的数量

摘要

现在我们知道,常数可以帮助我们编写干净的测试,并减少编写新测试和维护现有测试所需的工作量。 将本博客文章中给出的建议付诸实践时,我们需要记住以下几点:

  • 我们必须给常量和常量类起好名字 。 如果我们不这样做,就不会利用这些技术的全部潜力。
  • 我们不应该在不弄清楚我们想要用该常数实现什么的情况下引入新常数。 实际情况通常比此博客文章的示例复杂得多。 如果我们在自动驾驶仪上编写代码,很可能会错过针对当前问题的最佳解决方案。

翻译自: https://www.javacodegeeks.com/2014/05/writing-clean-tests-beware-of-magic.html

c++返回指针时候注意提防

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

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

相关文章

无线网桥的特点及应用方案

无线网桥顾名思义就是无线网络的桥接&#xff0c;它利用无线传输方式实现在两个或多个网络之间搭起通信的桥梁&#xff1b;无线网桥从通信机制上分为电路型网桥和数据型网桥。那么&#xff0c;无线网桥的特点及应用方案有哪些呢&#xff1f;接下来我们就一起来看看吧&#xff0…

Spring WebClient的单元测试

WebClient引用其Java文档是Spring Framework的 非阻塞&#xff0c;反应式客户端执行HTTP请求&#xff0c;通过底层HTTP客户端库&#xff08;如Reactor Netty&#xff09;公开流利的&#xff0c;反应式API 。 在我当前的项目中&#xff0c;我广泛使用WebClient进行服务到服务…

以太网的光猫和光纤的光猫有什么区别吗?

光调制解调器&#xff0c;光猫也称为单端口光端机&#xff0c;是针对特殊用户环境而研发的一种三件一套的光纤传输设备。该设备采用大规模集成芯片&#xff0c;电路简单&#xff0c;功耗低&#xff0c;可靠性高&#xff0c;具有完整的告警状态指示和完善的网管功能。光猫可以分…

SFP光模块基本概念及使用注意事项详解

光模块(optical module)由光电子器件、功能电路和光接口等组成&#xff0c;光电子器件包括发射和接收两部分。简单的说&#xff0c;光模块的作用就是光电转换&#xff0c;发送端把电信号转换成光信号&#xff0c;通过光纤传送后&#xff0c;接收端再把光信号转换成电信号。现在…

Java中的状态设计模式

在本教程中&#xff0c;我们将探讨另一种流行的行为设计模式-状态设计模式。 当我们使用可以存在于多个状态的对象时&#xff0c;状态设计模式的知识变得非常有用。 当对象的行为取决于其当前状态时&#xff0c;我们应该主要使用它。 这种模式有助于我们避免在该类的方法中对对…

串口服务器工作方式及常见异常故障问题排除方法介绍

串口设备联网服务器就像一台带CPU、实时操作系统和TCP/IP协议的微型电脑&#xff0c;方便在串口和网络设备中传输数据。您可以在世界任何位置通过网络&#xff0c;用您的计算机来存取&#xff0c;管理和配置远程的设备。但是我们在实际使用串口服务器的过程中&#xff0c;难免会…

E1立体声卡侬头(XLR) 音频编解码器产品介绍

FCA系列音频编解码器是一种采用数字处理芯片及大规模FPGA、数字编解码转换和时钟恢复技术方法设计的基于E1(2M)通道传输立体声广播信号的广播传送设备系统&#xff0c;它可以借助目前成熟可靠的E1传输系统网&#xff0c;建立起数字立体声广播传送系统网络&#xff0c;实现广播传…

E1视音频编解码器应用方案详细说明

E1音频编解码器&#xff0c;是采用数字处理芯片及大规模FPGA、数字编解码转换和时钟恢复技术方法设计的。适用于广播节目源传输的设备。音频编码器是将输入的立体声音频信号&#xff0c;经A/D数字编解码变换或数据格式转换后&#xff0c;重新成帧&#xff0c;形成串行数据流&am…

java请求接口示例_Java 8:功能接口示例

java请求接口示例为了支持Java 8中的lambda表达式&#xff0c;他们引入了Functional Interfaces。 具有单一抽象方法的接口可以称为功能接口。 Runnable&#xff0c;Comparator&#xff0c;Cloneable是功能接口的一些示例。 我们可以使用Lambda表达式实现这些功能接口。 例如…

Java中的外观设计模式

立面是指建筑物的外观。 当穿过街道时&#xff0c;我们所看到的只是建筑物的外观。 该图面抽象了建筑物的所有复杂实施细节。 同样&#xff0c; 外观设计模式旨在为子系统中的一组接口提供统一的接口。 这个统一的接口对客户端隐藏了子系统的复杂性。 它属于结构模式类别。 J…

串口服务器介绍及产品特点详解

串口服务器提供串口转网络功能&#xff0c;能够将RS-232/485/422串口转换成TCP/IP网络接口&#xff0c;实现RS-232/485/422串口与TCP/IP网络接口的数据双向透明传输。使得串口设备能够立即具备TCP/IP网络接口功能&#xff0c;连接网络进行数据通信&#xff0c;极大的扩展串口设…

串口服务器应用领域及应用方案详解

串口服务器提供串口转网络功能&#xff0c;使得串口设备能够立即具备TCP/IP网络接口功能&#xff0c;连接网络进行数据通信&#xff0c;极大的扩展串口设备的通信距离&#xff0c;应用领域非常广泛。接下来我们就来为大家详细介绍下串口服务器的应用领域及应用方案&#xff0c;…

将对象转换为Map并返回

在大型企业应用程序中&#xff0c;有时我们需要将数据对象与Map相互转换。 通常&#xff0c;这是特殊序列化的中间步骤。 如果可以使用某种标准&#xff0c;则最好使用该标准&#xff0c;但是很多时候&#xff0c;一些首席架构师所设想的体系结构&#xff0c;严格的环境或某些类…

多串口服务器的工作方式及接线示意图介绍

串口服务器提供串口转网络功能&#xff0c;能够将RS-232/485/422串口转换成TCP/IP网络接口&#xff0c;实现RS-232/485/422串口与TCP/IP网络接口的数据双向透明传输。那么&#xff0c;多串口服务器是怎么工作&#xff0c;怎么接线的&#xff1f;接下来就由飞畅科技小编一起来为…

多路串口服务器的应用及应用范围介绍

串口服务器的应用领域很是广泛&#xff0c;主要应用在门禁系统、考勤系统、售贩系统、POS系统、楼宇自控系统、自助银行系统、电信机房监控、电力监控等。接下来就由飞畅科技的小编来为大家详细介绍下多路串口服务器的应用及应用范围&#xff0c;感兴趣的朋友就一起来看看吧&am…

javafx 调用接口_JavaFX技巧3:使用回调接口

javafx 调用接口作为UI框架开发人员&#xff0c;提供自定义控件外观和行为的方法是我工作的一部分。 在许多情况下&#xff0c;这是通过允许框架用户在控件上注册工厂来完成的。 过去&#xff0c;我会为此创建一个工厂接口&#xff0c;并在框架内提供一个或多个默认实现。 这些…

工业串口服务器如何使用

串口联网服务器让传统的RS-232/422/485设备立即联网&#xff0c;利用基于TCP/IP的串口数据流传输的实现来控制管理的设备硬件是专为串口转以太网设计连接的桥梁。那么&#xff0c;我们该如何正确使用工业串口服务器呢&#xff1f;接下来我们就跟随飞畅科技的小编一起来看看吧&a…

JMetro 5.5版发布

JMetro 5.5版刚刚发布。 进行了重大更新&#xff0c;其中添加了一些错误修复&#xff0c;样式和功能。 一个新的主题测试器示例应用程序也已添加到示例子项目中&#xff0c;该应用程序测试了几项内容&#xff0c;例如控件之间的对齐。 我将尽量使这篇文章简短&#xff0c;因为…

关于工业级RS485串口服务器的组网方式详解

工业级串口服务器提供串口转网络功能&#xff0c;是实现串口&#xff08;TTL串口或RS232/RS485/RS422&#xff09;数据与TCP/IP协议数据相互转换实现数据通过网络传输的工业互联通讯设备。通过连接多个串口设备并将串口数据流进行选择和处理&#xff0c;将串口数据转换为以太网…

什么是四路串口服务器?

四路串口RS232/RS422/RS485设备联网服务器&#xff08;以下简称&#xff1a;串口服务器&#xff09;是由杭州飞畅科技自主研发的串口设备联网产品&#xff0c;其中RS232/RS422/RS485可以任意组合使用(客户可定制&#xff09;。那么&#xff0c;什么是四路串口服务器&#xff1f…