修改了 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 < 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;
}
#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;
}