无线监控系统之三-------测试与扩展
无线监控系统之三-------测试与扩展
测试是一个程序必不可少的部分,一个程序至少需要检验是否可以按要求运行,有源码的朋友也许会发现源码中有一些临时的嵌套在程序中的测试用例,对某些用例我做一个简单的介绍。
测试一:该测试主要用于在串口通讯还没连通时的,屏蔽掉获取串口数据的代码,给数据数组初始化一个正常的数据帧,测试用户显示界面能否显示正常的数据。 TemVlueThd.cs
dataa = new byte[21]{ 0xaa, 0x01, 0x10, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x11, 0x02, 0x02, 0x00, 0xe5}; //读取数据 //if (cci.getdata() == null) return; //Array.Copy(cci.getdata(), dataa, n);
DataDisplyForm.cs
public void showTemDisplyValue(byte[] dataaa) //委托,数据处理及显示 { string v = Convert.ToString(COMMONDEAL.DataConversion.Hex2Ten(COMMONDEAL.DataConversion.LenByte(dataaa[0].ToString(), 2) + COMMONDEAL.DataConversion.LenByte(dataaa[1].ToString(), 2))); //获取传送的数据 //txttest.Text = COMMONDEAL.DataConversion.LenByte(tdata[0].ToString("x").Trim() + tdata[1].ToString("x").Trim(), 2); //测试 txttest.Text = v; //测试 string rv = null; ........ ........ } 上面两个测试主要是用于测试串口数据接受前后检测数据在程序中是否可以正常传输,由于前面的程序都是根据类模型图一口气写完的,一开始还担心写得太乱,会调死人去~...~,开始时碰到了一点小问题,我屏蔽掉了TimIntvArth.cs中的一些数据限制代码(见下程序),哈哈,通了。。。高兴啊,小问题,易解决了。 TimIntvArth.cs public byte[] dealData(byte[] framdata) //数据帧处理函数 { //if (!framdata[0].ToString("x").Trim().Equals("aa")) return null; //if (!framdata[2].ToString("x").Trim().Equals("11")) return null; //if ((!framdata[4].ToString("x").Trim().Equals("3")) && (!framdata[4].ToString("x").Trim().Equals("2"))) return null; // int textds = 0; // for (int j = 0; j < n - 2; j++) //计算前20字节数之和 //{ //textds += Convert.ToInt32(COMMONDEAL.DataConversion.Hex2Ten(framdata[j].ToString("x").Trim())); // } //int efficy = Convert.ToInt32(COMMONDEAL.DataConversion.Hex2Ten(framdata[n - 2].ToString("x").Trim() + framdata[n - 1].ToString("x").Trim())); //计算效验码值 // if (textds != efficy) { return null; } ........ ........ } 下面我重点讲讲系统设计可以扩展的地方,呵呵,这也许是设计模式设计的好处吧,再次推荐GOF的<<设计模式--可复用面向对象软件的基础>>一书,你会有异想不到的收获。 系统可扩展的第一个地方----通讯方式的扩展,大家可以看UML图(上位机与下位机数据通讯方式接口图,呵呵,朋友再点击一次第一部分喽),我现在实现的是串口通讯的程序,有兴趣的朋友可以实现其它三种通讯中的一种,然后只要在主窗口把通讯方式在cFlag类中设定为你需要的通讯方式即可。 系统可扩展的第二个地方---数据帧的扩展(数据帧接口图),通讯系统的数据帧格式并不是一成不变的,数据帧会根据实际需要而增加,如果我们把所有的数据帧都写在一个类里,到时累死的是我们,烦死的是后来者了。。。。刚好,这个部分我可以举个例子,细心的朋友可能会看到资源管理器中的DATAFRAME包中有两个类我以前没介绍过----TimIntvArth.cs和TimIntvData.cs,这两个类是用来实现系统向外界发送数据,看看源码吧~~ using System;
using System.Collections.Generic; using System.Text; /************ * 功能:采集时间间隔数据帧 **********************/ namespace LOGICDEAL.DATAFRAME { class TimIntvData:DataFrameInter { private ArthFrameInter afi = null; //工厂模式:对应的数据帧处理类 private int n=18, m=9; public TimIntvData() { } public byte[] dealFrame(byte[] frame) //接收数据帧函数,温度值数据帧长度为21字节 { if (afi.dealData(frame) == null) return null; byte[] adata = new byte[m]; //需要输出的字节数组,长度为9字节 Array.Copy(afi.dealData(frame), adata, m); //adata = afi.dealData(frame); return adata; } public byte[] sendFrame() //发送数据帧函数 { byte[] a = new byte[10]; return a; } public void setAFI() //获取数据帧处理类实例 { this.afi = new TimIntvArth(); } } } using System; using System.Collections.Generic; using System.Text; /************ * 功能:采集时间间隔数据帧处理 * **********************/ namespace LOGICDEAL.DATAFRAME { class TimIntvArth:ArthFrameInter { private int n = 22, m = 9; public byte[] dealData(byte[] framdata) //数据帧处理函数 { if (!framdata[0].ToString("x").Trim().Equals("aa")) return null; if (!framdata[2].ToString("x").Trim().Equals("11")) return null; if ((!framdata[4].ToString("x").Trim().Equals("3")) && (!framdata[4].ToString("x").Trim().Equals("2"))) return null; int textds = 0; for (int j = 0; j < n - 2; j++) //计算前20字节数之和 { textds += Convert.ToInt32(COMMONDEAL.DataConversion.Hex2Ten(framdata[j].ToString("x").Trim())); } int efficy = Convert.ToInt32(COMMONDEAL.DataConversion.Hex2Ten(framdata[n - 2].ToString("x").Trim() + framdata[n - 1].ToString("x").Trim())); //计算效验码值 if (textds != efficy) { return null; } byte[] adata = new byte[m]; adata[0] = framdata[5]; //提取数据,2字节 adata[1] = framdata[6]; adata[2] = framdata[13]; //提取源地址,2字节 adata[3] = framdata[14]; adata[4] = framdata[15]; //提取网络地址,2字节 adata[5] = framdata[16]; adata[6] = framdata[17]; //网络号,1字节 adata[7] = framdata[18]; //提取通道,1字节 adata[8] = framdata[19]; //提取RSSI,1字节 return adata; } } } 系统可扩展的第三个地方---用户窗体与数据逻辑层的处理线程类(见用户窗体与数据逻辑层的处理线程类图),当初也不知道为什么要弄个线程类,呵呵,现在可想清楚了,这个线程啊主要是用来进行各数据帧的业务处理的,包括从获取通讯方式、获取数据帧类型和从通讯端口获取(传送)数据,这是个策略性问题了,通讯方式和数据帧类型的组合就是一种策略,如为采集时间间隔数据帧格式设置的TimIntvThd类。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Threading; /************ * 功能:采集时间间隔数据帧线程类 * **********************/ namespace LOGICDEAL.DEALTHREAD { public class TimIntvThd:DealThread { private COMMUNICATE.CommunicateInter cci = null; //通讯类型 private DATAFRAME.DataFrameInter dfi = null; //数据帧 //private Thread thread = null; //线程 byte[] dataa = null; private int n = 18, m = 9; private byte[] dataf = null; public TimIntvThd(byte[] data) //构造函数 { dataf=new byte[n]; dataf = data; //Array.Copy(data, dataf, n); init(); } public override void init() { this.cci = COMMUNICATE.Cflag.getCtype(); //初始化通讯类 //this.dfi = new DATAFRAME.TimIntvData(); //初始化数据帧类 //dfi.setAFI(); this.thread = new Thread(new ThreadStart(this.run)); //申请线程 //throw new Exception("The method or operation is not implemented."); } public override void run() //线程运行的方法 { cci.Write(dataf); cci.Write(dataf); } } } 系统可扩展的第四个地方---用户窗口公共接口(见用户窗口公共接口图),这个接口主要用来为各用户窗体需要的数据处理线程提供一个统一接口,用户窗体中可以根据需要来设计一个或多个数据处理线程,如扩展中的TimIntevForm.窗体,代码如下: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; /************ * 功能:采集时间间隔设置 * **********************/ namespace BUSINESSMANAGE { public partial class TimIntevForm : Form,DataFormInter { DATAACCESS.DbOperation db = null; string ipaddr = null; string channelnum = null; private LOGICDEAL.DEALTHREAD.TimIntvThd tit; private byte[] dataf=null; public TimIntevForm(string ipaddr, string channelnum) { db = new DATAACCESS.DbOperation(); this.ipaddr = ipaddr; this.channelnum = channelnum; InitializeComponent(); } private void btnSure_Click(object sender, EventArgs e) { if (txtTimintv.Text.Contains(".")) { MessageBox.Show("时间间隔不能为小数!", "确定", MessageBoxButtons.OK, MessageBoxIcon.Information); txtTimintv.Focus(); return; } setupfram(); } private void btnCancl_Click(object sender, EventArgs e) { this.Close(); } private void setText() { DataTable dt = db.getData("select a.ipaddr,a.channelnum,a.reltinter,a.instinter ,a.unitnum ,a.timintv ,b.netaddress,b.netnum from t_channal a,t_node b where a.ipaddr=b.ipaddr and a.ipaddr=’" + ipaddr + "’ and a.channelnum=’"+channelnum+"’"); char[] a = new char[] { ’~’ }; txtIpaddr.Text = dt.Rows[0][0].ToString(); txtChannelnum.Text =dt.Rows[0][1].ToString(); txtunit.Text = dt.Rows[0][4].ToString(); txtTimintv.Text = dt.Rows[0][5].ToString(); string instiner = dt.Rows[0][3].ToString(); string reltinter = dt.Rows[0][2].ToString(); txtReltinters.Text = reltinter.Split(a)[0].ToString(); txtReltinterx.Text = reltinter.Split(a)[1].ToString(); txtInstinters.Text = instiner.Split(a)[0].ToString(); txtInstinterx.Text = instiner.Split(a)[1].ToString(); txtNetnum.Text = dt.Rows[0][7].ToString(); txtNetaddress.Text = dt.Rows[0][6].ToString(); } private void setupfram() { dataf=new byte[18]; dataf[0] = 0xaa; dataf[1] = 0x01; dataf[2] = 0x0d; //数据长度 dataf[3] = 0x01; //消息类型 string daa = COMMONDEAL.DataConversion.Ten2Hex(txtTimintv.Text.ToString()); daa = COMMONDEAL.DataConversion.LenByte(daa,4); dataf[4] = (byte)Convert.ToSByte(daa.Substring(0, 2),16); //数据sss dataf[5] = (byte)Convert.ToSByte(daa.Substring(2, 2),16); dataf[6] = 0x01; //保留 dataf[7] = 0x01; dataf[8] = 0x01; dataf[9] = 0x01; dataf[10] = 0x01; dataf[11] = 0x01; dataf[12] = (byte)Convert.ToSByte(txtNetaddress.Text.ToString().Substring(0, 2),16); //网络地址 dataf[13] = (byte)Convert.ToSByte(txtNetaddress.Text.ToString().Substring(2, 2),16); dataf[14] = (byte)Convert.ToSByte(txtNetnum.Text.ToString(),16); //网络号 dataf[15] = (byte)Convert.ToSByte(txtChannelnum.Text.ToString(),16); //通道号 int t = 0; //计算前16字节数之和,计算校验码 for (int i = 0; i < 16; i++) { t += dataf[i]; } string temp = COMMONDEAL.DataConversion.LenByte(COMMONDEAL.DataConversion.Ten2Hex(t.ToString()), 4); dataf[16] = (byte)Convert.ToSByte(temp.Substring(0, 2), 16); dataf[17] = (byte)Convert.ToSByte(temp.Substring(2, 2), 16); tit = new LOGICDEAL.DEALTHREAD.TimIntvThd(dataf); tit.start(); } private void TimIntevForm_Load(object sender, EventArgs e) { setText(); } public void init(){} public void start(){} public void run(){} } } 第三部分就这样吧,设计肯定有许多漏洞,望各位多提意见了。。。 待续第四部分无线监控系统之四-------结言
参考文档:
无线监控系统之一-------UML设计 无线监控系统之二-------C#实现 [原创]无线监控系统之二-------C#实现(续) 无线监控系统之四-------结言 CS系统三层架构扩展支持WCF及策略模式应用(原创) 软件开发与设计 - MIS-管理信息系统--地下水监控管理信息系统 软件开发与设计 - MIS-管理信息系统-财政资金监控管理系统 软件开发与设计 - MIS-管理信息系统(监控类数据库设计) 软件开发与设计 - MIS-管理信息系统(XX某项目数据库表) 软件开发与设计 - CMS内容管理系统-[CMS程序]SXCMS文章管理系统 2.0 测试版 软件开发与设计 - MIS-管理信息系统(江苏省无线电科学研究所有限公司数据库设计) C# Winform 软件用户授权注册系统V2.1 测试程序(Tester.exe) C/S开发框架的角色(Role)分类(普通角色、系统角色、数据角色、扩展角色) 软件开发与设计 - EMS-电子商城系统-[电子商务]Hstear Shop 仿淘宝C2C商城测试版 WinFramework轻量框架-客户案例-煤矿智能防尘监测监控MES系统平台
其它资料:
什么是C/S结构? | C/S框架核心组成部分 | C/S框架-WebService部署图 | C/S框架-权限管理 | C/S结构系统框架 - 5.1旗舰版介绍 | C/S结构系统框架 - 功能介绍 | C/S结构系统框架 - 产品列表 | C/S结构系统框架 - 应用展示(图) | 三层体系架构详解 | C/S架构轻量级快速开发框架 | C/S框架网客户案例 | WebApi快速开发框架 | C/S框架代码生成器 | 用户授权注册软件系统 | 版本自动升级软件 | 数据库底层应用框架 | CSFramework.CMS内容管理系统 | |