单元测试如何调用Socket服务
================

#### 问题现象

在[单元测试框架](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/unittest-guidelines#概述)中，如何对Socket服务进行测试。

#### 背景知识

在[NetWork Kit](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/net-mgmt-overview)中，[Socket连接](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/socket-connection#简介)是实现网络通信的重要功能模块，支持TCP/UDP/Multicast/TLS协议。

#### 解决方案

将待测设备既作为服务端又作为客户端，启动服务端和客户端，完成消息的自发自收。

1.  使用Socket服务需要在module.json5中申请ohos.permission.INTERNET权限。
    
    "requestPermissions": \[
      {
        "name": "ohos.permission.INTERNET",
      }
    \],
    
2.  在entry/src/ohosTest/ets/test目录下新建socketSelf.test.ets，实现服务端监听127.0.0.1:8080，客户端连接统一端口并发送HelloHypium，服务端收到原文后，在前面拼接Echo:再发回，客户端把回包内容与预期值做断言，判断是否相同。
    
    import { describe, it, expect } from '@ohos/hypium';
    import { socket } from '@kit.NetworkKit'
    const TAG: string \= 'SocketSelfTest';
    
    export default function socketSelfTest() {
      describe('SocketSelfCommunicationTest', () \=\> {
        it('手机自发自收 – 服务端+客户端在同一设备', 0, async (done: Function) \=\> {
         _ /\* ================= 1. 启动服务端 ================= \*/_
          const server \= socket.constructTCPSocketServerInstance();
          const addr: socket.NetAddress \= {
            address: '127.0.0.1',
            port: 8080,
            family: 1
          };
    
         _ // 一步完成“绑定+监听”_
          await new Promise<void\>((resolve, reject) \=\> {
            server.listen(addr, (err) \=\> {
              if (err) {
                console.error(\`${TAG} server listen fail: ${JSON.stringify(err)}\`);
                reject(err);
              } else {
                console.info(\`${TAG} server listening...\`);
                resolve();
              }
            });
          });
    
         _ // 订阅server的connect事件，客户端与服务端建立连接后，返回一个TCPSocketConnection对象，用于与客户端通信（仅注册事件，不阻塞）_
          server.on('connect', (clientSocket: socket.TCPSocketConnection) \=\> {
            console.info(\`${TAG} client on connected\`);
          _  // clientSocket即为建立连接后获取到的连接对象，可以通过该对象订阅TCPSocketConnection相关的事件_
            _// 服务端接收到客户端发送的信息HelloHypium_
            clientSocket.on('message', (value: socket.SocketMessageInfo) \=\> {
              let buffer \= value.message;
              let dataView \= new DataView(buffer);
              let str \= "";
              for (let i \= 0; i < dataView.byteLength; ++i) {
                str += String.fromCharCode(dataView.getUint8(i));
              }
              console.info(\`${TAG} server received message: ${str}\`);
              console.info(\`${TAG} server received address: ${value.remoteInfo.address}\`);
             _ // 向客户端发送数据Echo:HelloHypium_
              clientSocket.send({ data: \`Echo:${str}\` });
              console.info(\`${TAG} server send message: Echo:${str}\`)
            });
          });
    
         _ /\* ================= 2. 启动客户端 ================= \*/_
          const client \= socket.constructTCPSocketInstance();
          const resp \= await new Promise<string\>((resolve, reject) \=\> {
            client.connect({ address: addr, timeout: 5000 }, (err) \=\> {
              if (err) {
                console.error(\`${TAG} client connect fail: ${JSON.stringify(err)}\`);
                reject(err);
                return;
              }
              console.info(\`${TAG} client start connected\`);
    
         _     // 连接成功之后，向服务端发送数据HelloHypium_
              client.send({ data: 'HelloHypium' }, (err) \=\> {
                if (err) {
                  console.error(\`${TAG} client send fail: ${JSON.stringify(err)}\`);
                  reject(err);
                  return;
                }
                console.info(\`${TAG} client send message: HelloHypium\`);
              });
    
             _ // 监听message事件，接收到消息时，执行回调函数_
              client.on('message', (value: socket.SocketMessageInfo) \=\> {
                let buffer \= value.message;
                let dataView \= new DataView(buffer);
                let str \= "";
                for (let i \= 0; i < dataView.byteLength; ++i) {
                  str += String.fromCharCode(dataView.getUint8(i));
                }
                console.info(\`${TAG} client received: ${str}\`);
                client.close();
                resolve(str);
              });
            });
          });
    
       _   /\* ================= 3. 断言 & 清理 ================= \*/_
          console.info(\`${TAG} resp: ${resp}\`);
          expect(resp).assertEqual('Echo:HelloHypium');
          server.off("connect");
          client.off("message");
          client.off("close");
          done();
        });
      });
    }