|
Posted on 2009-02-01 23:09 S.l.e!ep.¢% 阅读(1543) 评论(0) 编辑 收藏 引用 所属分类: test
修改了 INetwordable 接口, 将网络程序中的“网络通信”抽离出来,方便写单元测试 #include <windows.h>
#include <iostream>
using namespace std;

// 网络通信协议
 /**/////////////////////////////////////////////////////////////////////////////// // struct cmd
  {
int nCmd;
};

#pragma pack(1)
struct tagClientLogin
  {
cmd header;
char username[ 20 ];
char userpwd[ 20 ];
} ;

struct tagRepClientLogin
  {
cmd header;
bool bLoginSuccess;
};
#pragma pack(1)

#define NETWORK_CMD_LOGIN 1
#define NETWORK_CMD_REP_LOGIN 2
 /**///////////////////////////////////////////////////////////////////////////////// 
// 接口定义
 /**///////////////////////////////////////////////////////////////////////////////// class ClientObserver
  {
public :
 ClientObserver() {}
 ~ ClientObserver() {}
virtual void onRepLogin( bool bLoginSuccess) = 0 ;
} ;

 /**//*
class INetWorkable
{
public :
INetWorkable() {}
~INetWorkable() {}
// pvoid : 欲发送的缓冲区; nSize : 缓冲区的大小
virtual bool send( const void * pvoid, int nSize) = 0 ;
// 由网络层调用,pvoid: 接收到的数据的缓冲区, nSize : 缓冲区的大小; 返回已经处理的数据长度
virtual int onreceive( const void * pvoid, int nSize) = 0 ;
};
*/

// 将原先的 INetWorkable 接口拆分成两个类
class INetWorkSendable
  {
public :
 INetWorkSendable() {}
 ~INetWorkSendable() {}
// pvoid : 欲发送的缓冲区; nSize : 缓冲区的大小
virtual bool send( const void * pvoid, int nSize) = 0 ;
};

class INetWorkRecvable
  {
public :
 INetWorkRecvable() {}
 ~INetWorkRecvable() {}
// 由网络层调用,pvoid: 接收到的数据的缓冲区, nSize : 缓冲区的大小; 返回已经处理的数据长度
virtual int onreceive( const void * pvoid, int nSize) = 0 ;
};

class ILogable
  {
public :
 ILogable() {}
 ~ ILogable() {}
virtual void log(const char* plog) = 0;
};
 /**///////////////////////////////////////////////////////////////////////////////// 
// 业务逻辑类
// Client 现在只需要继承 INetWorkRecvable 即可
 /**///////////////////////////////////////////////////////////////////////////////// class Client : public INetWorkRecvable
  {
public :
Client()
 {
m_pClientObserver = NULL;
m_plog = NULL;
m_pSendable = NULL;
}

 virtual ~Client() {}
 void registerObserver(ClientObserver * p) { m_pClientObserver = p; }
 void removeObserver() { m_pClientObserver = NULL; }
 void setLoger(ILogable * p) { m_plog = p; }
 void removeLoger() { m_plog = NULL; }
 void setSendable(INetWorkSendable* p) { m_pSendable = p; }
 void removeSendable(INetWorkSendable* p) { m_pSendable = NULL; }
bool SendLogin(const char* name, const char* pwd)
 {
tagClientLogin login;
memset( & login, 0 , sizeof (login));
login.header.nCmd = NETWORK_CMD_LOGIN;
strncpy(login.username, name, sizeof (login.username));
strncpy(login.userpwd, pwd, sizeof (login.userpwd));

// Sendable 改成了 "组合" 的方式后,每次调用 Send 都要判断, 让我很不爽
if( m_pSendable != NULL )
 {
return m_pSendable->send(&login, sizeof (login));
}
else
 {
return false;
}
}
protected :
virtual int onreceive( const void * pvoid, int nSize)
 {
if ( nSize < sizeof (cmd) )
return 0 ;
cmd * pheader = (cmd * )pvoid;
if ( pheader -> nCmd == NETWORK_CMD_REP_LOGIN )
 {
if ( nSize < sizeof (tagRepClientLogin) )
return 0 ;
tagRepClientLogin * ptagRepClientLogin = (tagRepClientLogin * )pvoid;
if ( m_pClientObserver != NULL )
m_pClientObserver -> onRepLogin(ptagRepClientLogin -> bLoginSuccess);
return sizeof (tagRepClientLogin);
}
return 0 ;
}
private :
ClientObserver * m_pClientObserver;
ILogable * m_plog;
INetWorkSendable* m_pSendable;
} ; 测试例子 #include "client.h"
#include <string.h>

class testClient : public Client, INetWorkSendable
  {
public:
 testClient() { memset(m_buf, 0, sizeof(m_buf)); }
 ~testClient() {}
int NetWorkReceive(const void* pvoid, int nSize)
 {
return onreceive(pvoid, nSize);
}

virtual bool send(const void * pvoid, int nSize)
 {
copyMemory(pvoid, nSize);
return true;
}
bool cmpMemory(const void* pvoid, int nSize)
 {
return ( 0 == memcmp(m_buf, pvoid, nSize) );
}
void copyMemory(const void* pvoid, int nSize)
 {
memcpy(m_buf, pvoid, nSize);
}

private:
char m_buf[1024];
};

int main()
  {
testClient test;
test.setSendable((INetWorkSendable*)&test);

test.SendLogin("test_username", "test_pwd");
tagClientLogin clientlogin;
memset(&clientlogin, 0, sizeof(clientlogin));
clientlogin.header.nCmd = NETWORK_CMD_LOGIN;
strcpy(clientlogin.username, "test_username");
strcpy(clientlogin.userpwd, "test_pwd");
if( !test.cmpMemory(&clientlogin, sizeof(clientlogin)) )
cout << "test failed" << endl;
 char szBuf[1024] = {0};
// 摸拟服务器发送的包长度不足
if( 0 != test.NetWorkReceive(szBuf, sizeof(tagRepClientLogin) - 10) )
cout << "test failed" << endl;
// 摸拟服务器发送的包内容非法
if( 0 != test.NetWorkReceive(szBuf, sizeof(tagRepClientLogin)) )
cout << "test failed" << endl;
tagRepClientLogin repLogin;
repLogin.header.nCmd = NETWORK_CMD_REP_LOGIN;
memcpy(szBuf, &repLogin, sizeof(repLogin));
// 摸拟服务器发送了正确的包
if( sizeof(tagRepClientLogin) != test.NetWorkReceive(szBuf, sizeof(tagRepClientLogin)) )
cout << "test failed" << endl;
return 0;
}
|