zoukankan      html  css  js  c++  java
  • 让你提前认识软件开发(19):C语言中的协议及单元測试演示样例

    第1部分 又一次认识C语言

    C语言中的协议及单元測试演示样例

     

    【文章摘要】

            在实际的软件开发项目中。常常要实现多个模块之间的通信。这就须要大家约定好相互之间的通信协议,各自依照协议来收发和解析消息。

           本文以实际的程序代码为例,详细介绍了如何用C语言来实现通信协议,并基于对协议字段的推断,说明了程序单元測试的过程,为相关的开发工作提供了故意的參考。

    【关键词】

           软件开发  协议  单元測试  C语言  字段

     

    一、软件模块之间的协议

            什么是软件模块之间的协议?不同的软件模块之间要实现相互通信,就必须遵循共同的消息规范。大家依照约定好的规范来收发消息。软件模块之间的协议就是不同模块间消息交互的规范。

            在通信协议中,一条完整的消息由消息头和消息体构成,如图1所看到的。

    1 一条完整的消息示意图

            在C语言中。用结构体来表示协议。在进行消息解析的时候,一般仅仅关注消息体的内容。

    消息头仅仅是用于标识一条消息。让其他模块能够识别该类消息。

     

    二、单元測试

           在提交程序版本号之前,开发者须要对代码进行单元測试和集成測试。

    那么什么是单元測试呢?单元測试就是对程序中的一个函数进行測试。看对于某个输入,是否有预期的输出。

           单元測试的示意图如图2所看到的。

    2 单元測试的示意图

            能够把函数看成一个灰色的盒子,測试的时候仅仅关心输入和输出,要设计多组单元測试数据来对函数的功能进行測试。

            此外,在測试中。另一个叫做“測试用例”的概念。測试用例就是一次測试的整个过程,包含:測试目的、预置条件、測试步骤、预期结果、通过准则、測试工具等。

     

    三、本程序中的协议

            本程序中的协议包含了消息头和消息体。当中。消息头有四个字段。消息体有五个字段。

    例如以下代码所看到的。

    // 消息头结构

    typedef struct

    {

        UINT16  iReserve1;

        UINT16  iReserve2;

        UINT16  iReserve3;

        UINT16  iReserve4;

    }MsgHead_T;

     

    // 消息结构体(包含消息头和消息体)

    typedef struct

    {

        MsgHead_T    MsgHead;                       // 消息头

        UINT32       iOperType;                         // 操作类型

        UINT8        szUserNumber[30];            // 用户号码

        UINT8        szOperTime[20];                // 操作时间, 格式为: yyyymmdd

        UINT32       iReserve1;                          // 保留字段1

        UINT8        szReserve2[50];                 // 保留字段2

    }UserReqMsg_T;

     

            在消息体的五个字段中。操作类型、用户号码和操作时间是本次要进行推断处理的字段。另外两个字段是保留字段,能够先不用赋详细的值。

            在协议中,为什么要留有保留字段呢?这是方便以后对协议进行扩展。

    也就是说,假设以后除了操作类型、用户号码和操作时间之外,还须要添加新的字段定义。能够直接利用扩展字段。这在实际的软件开发项目中是非常重要的。

     

    四、程序代码

            基于以上协议。本文中的程序代码例如以下所看到的:

    /**********************************************************************

    * 版权全部 (C)2014, Zhou Zhaoxiong。

    *

    * 文件名: UnitTest.c

    * 文件标识:无

    * 内容摘要:协议及单元測试演示样例代码

    * 其他说明:无

    * 当前版本号: V1.0

    *     者: Zhou Zhaoxiong

    * 完毕日期: 20140507

    *

    * 改动记录1// 改动历史记录, 包含改动日期、版本号号、改动人及改动内容

    * 改动日期:

    * 版本号号:

    * 改动人:

    * 改动内容:

    *

    **********************************************************************/

    #include <stdio.h>

    #include <string.h>

     

    // 重定义数据类型

    typedef unsigned char       UINT8;

    typedef unsigned short int    UINT16;

    typedef unsigned int        UINT32;

    typedef signed   int        INT32;

     

    // 消息头结构

    typedef struct

    {

        UINT16  iReserve1;

        UINT16  iReserve2;

        UINT16  iReserve3;

        UINT16  iReserve4;

    }MsgHead_T;

     

    // 消息结构体(包含消息头和消息体)

    typedef struct

    {

        MsgHead_T   MsgHead;                // 消息头

        UINT32      iOperType;      // 操作类型, 操作类型仅仅能为12

        UINT8       szUserNumber[30];         // 用户号码

        UINT8       szOperTime[20];      // 操作时间, 格式为: yyyymmdd

        UINT32       iReserve1;                // 保留字段1

        UINT8        szReserve2[50];           // 保留字段2

    }UserReqMsg_T;

     

    // 函数声明

    INT32 ProcUserReqMsg(UserReqMsg_T *ptUserReqMsg);

    INT32 main();

     

    /**********************************************************************

    * 功能描写叙述:主函数

    * 输入參数:无

    * 输出參数:无

    * 返回值: 0-运行完毕

    * 其他说明:无

    * 改动日期        版本号号              改动人         改动内容

    * --------------------------------------------------------------------------------------------------

    * 20140507         V1.0                zzx            创建

    ***********************************************************************/

    INT32 main()

    {

        UINT8  iRetVal          = 0;

        UINT32 iOperType        = 0;        // 操作类型

        UINT8  szUserNumber[30] = {0};      // 用户号码

        UINT8  szOperTime[10]  = {0};    // 操作时间, 格式为: yyyymmdd

     

        UserReqMsg_T tUserReqMsg = {0};     // 请求消息

     

        // 对消息头部进行赋值

        tUserReqMsg.MsgHead.iReserve1 = 1;

        tUserReqMsg.MsgHead.iReserve2 = 2;

        tUserReqMsg.MsgHead.iReserve3 = 3;

        tUserReqMsg.MsgHead.iReserve4 = 4;

     

        // 读入详细消息字段的值

        printf("操作类型: ");

        scanf("%d", &iOperType);

        printf("用户号码: ");

        scanf("%s", szUserNumber);

        printf("操作时间: ");

        scanf("%s", szOperTime);

     

        // 对详细消息字段进行赋值(保留字段可不赋值)

        tUserReqMsg.iOperType = iOperType;

        strncpy(tUserReqMsg.szUserNumber, szUserNumber, strlen(szUserNumber));// 获取号码, strncpy取代strcpy

        strncpy(tUserReqMsg.szOperTime,   szOperTime,   strlen(szOperTime));     // 获取时间, strncpy取代strcpy

     

        // 对消息体的字段进行异常推断

        iRetVal = ProcUserReqMsg(&tUserReqMsg);  // 注意: 传递參数的时候要加上&

        if (iRetVal == 0)      // 函数运行正确

        {

            // 打印消息字段内容

            printf("The user request message is: iOperType=%d, szUserNumber=%s, szOperTime=%s. ", tUserReqMsg.iOperType, tUserReqMsg.szUserNumber, tUserReqMsg.szOperTime);

            return 0;

        }

        else         // 打印异常消息

        {

            printf("Some content of the user request message is wrong, please check! ");

            return -1;

        }

    }

     

     

    /**********************************************************************

    * 功能描写叙述:对消息体的字段进行异常推断

    * 输入參数: ptUserReqMsg-用户请求消息

    * 输出參数:无

    * 返回值: 0-成功   其他-失败

    * 其他说明:无

    * 改动日期        版本号号              改动人         改动内容

    * --------------------------------------------------------------------------------------------------

    * 20140507         V1.0                zzx            创建

    ***********************************************************************/

    INT32 ProcUserReqMsg(UserReqMsg_T *ptUserReqMsg)

    {

        INT32  iRetValue      = 0;

     

        // 对输入參数进行异常推断

        if (ptUserReqMsg == NULL)

        {

            printf("ProcUserReqMsg(...): input parameter(ptUserReqMsg) is NULL. ");

     

            return -1;

        }

     

        // 对消息体字段进行异常推断

        if ((ptUserReqMsg->iOperType != 1) && (ptUserReqMsg->iOperType != 2))    // 操作类型仅仅能为12, 其他为数据异常

        {

            printf("ProcUserReqMsg(...): the iOperType is wrong, iOperType=%d. ", ptUserReqMsg->iOperType);

     

            return -2;

        }

       

        if (strlen(ptUserReqMsg->szUserNumber) != 8) // 用户号码异常, 长度8位才正确

        {

            printf("ProcUserReqMsg(...): the szUserNumber is wrong. ");

     

            return -3;

        }

     

        if (strlen(ptUserReqMsg->szOperTime) != 8)  // 操作时间异常, 长度8位才正确

        {

            printf("ProcUserReqMsg(...): the szOperTime is wrong. ");

           

            return -4;

        }

     

        return 0;

    }

     

           本程序要对ProcUserReqMsg函数进行单元測试。看该函数是否能对消息体的字段进行异常推断。

     

    五、单元測试用例

    1. 正常測试用例

           正常測试用例是指满足程序输入条件的測试用例。即观察程序在正确的输入情况下,是否能产生正确的输出。

           什么是正常測试?包含了两种情况:
            1) 输入正确的值,程序产生正确的输出。
            2) 输入错误的值。程序产生错误的输出。

           (1) “操作类型”为1

           设定“操作类型”为1,“用户号码”和“操作时间”字段均符合协议要求。程序的运行情况如图3所看到的。

    3 “操作类型”为1的正常运行情况

     

            (2) “操作类型”为2

            设定“操作类型”为2,“用户号码”和“操作时间”字段均符合协议要求。程序的运行情况如图4所看到的。

    4 “操作类型”为2的正常运行情况

     

    2. 异常測试用例

            异常測试用例是指不满足程序输入条件的測试用例,即观察程序在错误的输入情况下。产生的结果是如何的。

            什么是异常測试?包含了两种情况:
            1) 输入正确的值,程序产生错误的输出。


            2) 输入错误的值,程序产生正确的输出。

            (1) “操作类型”不为12

            设定“操作类型”为3(不为12的正整数),“用户号码”和“操作时间”字段均符合协议要求。程序的运行情况如图5所看到的。

    5 “操作类型”为3的异常运行情况

     

            (2) “用户号码”不是8

            设定“操作类型”为1,“用户号码”字段为9位。“操作时间”字段符合协议要求。程序的运行情况如图6所看到的。

    6 “用户号码”为9位的异常运行情况

     

            (3) “操作时间”不是8

            设定“操作类型”为1,“用户号码”符合协议要求,“操作时间”字段为9位。程序的运行情况如图7所看到的。

    7 “操作时间”为9位的异常运行情况

            正常和异常測试的情况都有非常多种,这里就不一一列举了。

    为了确保程序的正确性,一定要对程序(或者函数)进行充分的单元測试。

     

    七、总结

            对于协议。这是不同模块之间通信的桥梁。因此,在開始编码之前,一定要将协议定义清楚,这样也能够降低兴许改动带来的不便。

            对于单元測试,这是每一个软件开发project师都必须要认真对待的。

    单元測试进行得是否彻底。会直接影响到软件产品的质量。

            本文以实际的程序代码为样例。对用C语言表示协议和对代码进行单元測试作了详细的介绍。

    文中涉及到的协议表示方法和单元測试方法可供相关的软件开发project师參考。

    (欢迎訪问南邮BBS:http://bbs.njupt.edu.cn/)
    (欢迎訪问重邮BBS:http://bbs.cqupt.edu.cn/nForum/index)

    (本系列文章每周更新两篇,敬请期待!本人微博:http://weibo.com/zhouzxi?topnav=1&wvr=5。微信号:245924426,欢迎关注!)

  • 相关阅读:
    经历:如何设置jquery easyui中下拉框不可编辑
    经历:easyui的layout自适应高度布局
    JavaScript高级程序设计(九):基本概念----函数
    JavaScript高级程序设计(九):基本概念----语句的特殊点
    JavaScript高级程序设计(八):基本概念--操作符
    JavaScript高级程序设计(三):基本概念:数据类型
    JavaScript高级程序设计(七):JavaScript中的in关键字
    JavaScript高级程序设计(六):关键字 void 和 delete 使用
    JavaScript高级程序设计(五): js的关键字instanceof和typeof使用
    SQL Server 存储过程
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5182254.html
Copyright © 2011-2022 走看看