本系列内容,准备根据所完成的项目为基线,一步一步的把整个设计和实现过程梳理。

先从基本的一些环境问题入手,梳理清楚关于手机设备和Appnium。因为我们在后面的建立Appnium连接时,需要设备名字和启动的Appnium实例和对应的端口号。

一、获取手机设备

获取本机连接的设备,我们可以通过adb命令通过控制台来实现,在控制台中输入命令adb devices可得如下结果:

既然能

够如此简单的获取到连接的设备,接下来也就是对控制台文字进行处理分析,最后把需要内容获取出来展示在下拉框里即可.

对于获取到的结果,我们只取attached后面部分,可通过字符串的截取实现。去掉空格和换行符后,就变成了一连串的字符,由device间隔开的设备名字了,这样只需普通的字符处理即可完成。

实际代码如下,可供参考:

/// <summary>
/// 获取当前机器连接的终端设备
/// </summary>
/// <returns></returns>
public static string[] InitDevices()
{
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.UseShellExecute = false; //是否使用操作系统shell启动
p.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
p.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
p.StartInfo.RedirectStandardError = true;//重定向标准错误输出
p.StartInfo.CreateNoWindow = true;//不显示程序窗口
p.Start();//启动程序
//向cmd窗口发送输入信息
p.StandardInput.WriteLine("adb devices" + "&exit");
p.StandardInput.WriteLine("adb devices" + "&exit");
p.StandardInput.AutoFlush = true;
//p.StandardInput.WriteLine("exit");
//向标准输入写入要执行的命令。这里使用&是批处理命令的符号,表示前面一个命令不管是否执行成功都执行后面(exit)命令,如果不执行exit命令,后面调用ReadToEnd()方法会假死
//同类的符号还有&&和||前者表示必须前一个命令执行成功才会执行后面的命令,后者表示必须前一个命令执行失败才会执行后面的命令

//获取cmd窗口的输出信息
string output = p.StandardOutput.ReadToEnd();
string[] Devices = output.Replace("\r\n", "").Split(new string[] { "attached" }, StringSplitOptions.RemoveEmptyEntries)[1].Replace("\t", "").Replace(" ", "").Split(new string[] { "device" }, StringSplitOptions.RemoveEmptyEntries);
p.WaitForExit();//等待程序执行完退出进程
p.Close();
return Devices;

}

二、如何启动多个Appnium

    按照平常的使用方法,直接双击Appnium程序后点击启动即可启动一个默认端口为4723的Appnium实例。按照这种方法,貌似一台机器只能运行一个Appnium了。

不过笔者发现,在启动Appnium时,打印出一段代码样的东西:

通过这段代码,我发现Appnium的启动貌似是根据主要程序和一些配置来完成实例启动的。既然这样,那应该是可以通过修改IP、端口、平台和版本来控制启动的Appnium实例了。如果我想启动多个的话,

应该是可以通过配置端口号来运行多个Appnium了。果然,直接复制命令和配置文件的绝对路径,在控制台中执行,然后再观察对应的node程序,真的出现了!经过后期验证,这个通过命令实例话的

Appnium是可以运行的。

以此可得,通过对端口作为参数,启动Appnium实例的函数就这样实现了:

/// <summary>
/// 启动Appnium实例
/// </summary>
/// <param name="Port">启动Appnium端口</param>
public static void BootAppnium(string Port)
{
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.UseShellExecute = false; //是否使用操作系统shell启动
p.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
p.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
p.StartInfo.RedirectStandardError = true;//重定向标准错误输出
p.StartInfo.CreateNoWindow = true;//不显示程序窗口
p.Start();//启动程序

//向cmd窗口发送输入信息
string command = @"D:\Appium\node.exe D:\Appium\node_modules\appium\lib\server\main.js --address 127.0.0.1 --port " + Port + " --platform-name Android --platform-version 19 --automation-name Appium --language zh_CN --log-no-color" + "&exit";
p.StandardInput.WriteLine(command);
// p.StandardInput.WriteLine("netstat -aon|findstr \"127.0.0.1:47\"" + "&exit");
p.StandardInput.AutoFlush = true;
p.EnableRaisingEvents = true;

p.Close();

}

三、获取本机启动的Appnium

    知道了如何启动多个Appnium后,那获取本机启动的Appnium也就易如反掌了。我们可以通过获取到node.exe程序的PID值,然后根据PID值来获取对应的端口值了,当然我们在启动端口的时候,最好是预先

设定好一些范围,免得出现端口被占用的问题.

首先来获取node.exe的PID值:

C:\Users\Zeech>tasklist /v |findstr "node"
node.exe 6076 Console 9 78,948 K Unknown ZEECH_LEE\Zeech 0:00:03 暂缺

其中6076即对应的PID值,因为PID值是当前系统唯一的,所以可通过PID值获取到Appnium启动的端口号了

C:\Users\Zeech>netstat -ano |findstr "6076"
TCP 127.0.0.1:4723 0.0.0.0:0 LISTENING 6076

代码如下:

public static string getnodePID()
{
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.UseShellExecute = false; //是否使用操作系统shell启动
p.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
p.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
p.StartInfo.RedirectStandardError = true;//重定向标准错误输出
p.StartInfo.CreateNoWindow = true;//不显示程序窗口
p.Start();//启动程序

//向cmd窗口发送输入信息
p.StandardInput.WriteLine("tasklist /v |findstr \"node.exe\"" + "&exit");
// p.StandardInput.WriteLine("netstat -aon|findstr \"127.0.0.1:472\"" + "&exit");
p.StandardInput.AutoFlush = true;
//p.StandardInput.WriteLine("exit");
//向标准输入写入要执行的命令。这里使用&是批处理命令的符号,表示前面一个命令不管是否执行成功都执行后面(exit)命令,如果不执行exit命令,后面调用ReadToEnd()方法会假死
//同类的符号还有&&和||前者表示必须前一个命令执行成功才会执行后面的命令,后者表示必须前一个命令执行失败才会执行后面的命令

//获取cmd窗口的输出信息
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();//等待程序执行完退出进程
p.Close();
string nodePID = (((output.Replace("\r\n", "").Replace(" ", "").Split(new string[] { "node.exe", "Console" }, StringSplitOptions.RemoveEmptyEntries))))[2].ToString();

return nodePID;
}

/// <summary>
/// 获取当前机器运行的Appnium
/// </summary>
/// <returns></returns>
public static string [] InitAppnium()
{
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.UseShellExecute = false; //是否使用操作系统shell启动
p.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
p.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
p.StartInfo.RedirectStandardError = true;//重定向标准错误输出
p.StartInfo.CreateNoWindow = true;//不显示程序窗口
p.Start();//启动程序

//向cmd窗口发送输入信息
p.StandardInput.WriteLine("netstat -aon|findstr \""+ getnodePID()+"\"" + "&exit");
// p.StandardInput.WriteLine("netstat -aon|findstr \"127.0.0.1:472\"" + "&exit");
p.StandardInput.AutoFlush = true;
//p.StandardInput.WriteLine("exit");
//向标准输入写入要执行的命令。这里使用&是批处理命令的符号,表示前面一个命令不管是否执行成功都执行后面(exit)命令,如果不执行exit命令,后面调用ReadToEnd()方法会假死
//同类的符号还有&&和||前者表示必须前一个命令执行成功才会执行后面的命令,后者表示必须前一个命令执行失败才会执行后面的命令

//获取cmd窗口的输出信息
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();//等待程序执行完退出进程
p.Close();
string[] Appniuma = (((output.Replace("\r\n", "").Replace(" ", "").Replace("0.0.0.0:0", "||0.0.0.0:0").Split(new string[] { "TCP", "6076" }, StringSplitOptions.RemoveEmptyEntries))));
List<string> Appnium=new List<string>();
for (int i = 0; i < Appniuma.Count(); i++)
{
if (i>1)
{
Appnium.Add(Appniuma[i]);
}
}
return Appnium.ToArray();
}

注意:这种字符串截取的过程可能会出现一些bug.例如,在某些情况下,该PID值恰好是某个端口号的部分,那也会诶筛选出来,最完美的做法是只匹配PID值,这样处理一下就可以避免这种情况了.

当然,可能在其他的处理过程中同意会出现筛选不精确的情况,需要多次调试分析尽量做到精准.Windows下,可下载一个AWK插件,可以对列进行筛选处理会方便很多.在处理替换时,可能读者会发

现Replace("0.0.0.0:0", "||0.0.0.0:0"),其实这里的目的是隔开监听状体下的端口号,防止混乱.

四、销毁Appnium实例

    销毁与创建过程互为逆过程,有了以上知识,处理起来就非常简单了。只需要kill 实例程序node.exe即可.

直接上代码:

/// <summary>
/// 销毁Appnium实例
/// </summary>
public static void ExitAppnium()
{
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.UseShellExecute = false; //是否使用操作系统shell启动
p.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
p.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
p.StartInfo.RedirectStandardError = true;//重定向标准错误输出
p.StartInfo.CreateNoWindow = true;//不显示程序窗口
p.Start();//启动程序

//向cmd窗口发送输入信息
p.StandardInput.WriteLine(@"taskkill /f /t /im node.exe" + "&exit");

p.StandardInput.AutoFlush = true;
p.EnableRaisingEvents = true;

p.Close();

}

五、总结

经过以上的梳理,在对环境的操作,需要用到大量的Windows命令。如果想实现一个完整的Windows平台自动化测试,需要对cmd命令比较熟悉。同时要实现一个功能,最

快速便捷的方法就是去弄懂其原理。任何事情在明白原理的情况下,处理起来都是得心应手,代码只是一个桥梁而已,相信以上的代码写出来后都会觉得非常简单,可以说

几乎全是一些字符串的处理。在测试的过程中,往往就需要对获取的结果进行处理分析,如何精确的获取到需要的信息将是测试是否成功的关键了。

    谢谢大家,我已经迫不及待的构思下一篇博文了!

【Appnium+C#+Winform自动化测试系列】一、获取本机连接的设备、启动多个Appnium和获取本机启动的Appnium的更多相关文章

  1. 【Appnium+C#+Winform自动化测试系列】前言

    目录(后期持续更新) 一.前言  1.为什么选择Appnium 最近这些年APP保持着持续的火热,对应的APP测试行业也是跟着水涨船高.由于市场的需求,APP测试平台也涌出大量的自动化测试工具. 在对 ...

  2. C# WinForm开发系列 - WebBrowser

    原文:C# WinForm开发系列 - WebBrowser 介绍Vs 2005中带的WebBrowser控件使用以及一些疑难问题的解决方法, 如如何正确显示中文, 屏蔽右键菜单, 设置代理等; 收集 ...

  3. C# WinForm开发系列 - GDI+【转】

    http://blog.csdn.net/blue_sky6/article/details/53811435?locationNum=6&fps=1 C# WinForm开发系列 - GDI ...

  4. angularjs自动化测试系列之jasmine

    angularjs自动化测试系列之jasmine jasmine参考 html <!DOCTYPE html> <html lang="en"> <h ...

  5. angularjs自动化测试系列之karma

    angularjs自动化测试系列之karma karma test with jasmine 更好的利用工具是为了让生活更美好. 需要安装的东西: npm install karma -g mkdir ...

  6. C# WinForm开发系列 - ListBox/ListView/Panel

    转自会飞的小猪文章 C# WinForm开发系列 - ListBox/ListView/Panel 在博客园看到了一篇博文,觉得很不错,就转载过来了.    包含自定义绘制的ListBox, 带拖动, ...

  7. RF+Appium框架自动化测试系列一之(Mac下Appium环境搭建)万事开头难

    消失了3个月,有一段时间没来园子更新博客了,各位看官见谅哈哈,消失是因为刚换了工作环境没外网,好多笔记没能及时的记录分享,以后有时间慢慢补上吧,这段时间主要接触了移动端app的自动化测试,公司为了快速 ...

  8. Android Camera开发系列(上)——Camera的基本调用与实现拍照功能以及获取拍照图片加载大图片

    Android Camera开发系列(上)--Camera的基本调用与实现拍照功能以及获取拍照图片加载大图片 最近也是在搞个破相机,兼容性那叫一个不忍直视啊,于是自己翻阅了一些基本的资料,自己实现了一 ...

  9. C# WinForm开发系列 - 文章索引

    该系列主要整理收集在使用C#开发WinForm应用文章及相关代码, 平时看到大家主要使用C#来开发Asp.Net应用,这方面的文章也特别多,而关于WinForm的文章相对少很多,而自己对WinForm ...

随机推荐

  1. hadoop balance均衡datanode存储不起作用问题分析

    前段时间因为hadoop集群各datanode空间使用率很不均衡,需要重新balance(主要是有后加入集群的2台机器磁盘空间比较大引起的),在执行如下语句: bin/start-balancer.s ...

  2. 【BZOJ4033】[HAOI2015] 树上染色(树形DP)

    点此看题面 大致题意: 给你一棵点数为N的带权树,要你在这棵树中选择K个点染成黑色,并将其他的N-K个点染成白色.要求你求出黑点两两之间的距离加上白点两两之间距离的和的最大值. 树形\(DP\) 这道 ...

  3. python_62_装饰器5

    import time def timer(func): #timer(test1) func=test1 def deco(*args,**kwargs): start_time=time.time ...

  4. 从多个textarea中随机选取一个内容

    <div id="IMContentTest"> <textarea name="IMContent" class="IMClass ...

  5. C# 接口慨述

    接口(interface)用来定义一种程序的协定.实现接口的类或者结构要与接口的定义严格一致.有了这个协定,就可以抛开编程语言的限制(理论上).接口可以从多个基接口继承,而类或结构可以实现多个接口.接 ...

  6. C# 常用函数和方法集汇总

    1.DateTime 数字型 System.DateTime currentTime=new System.DateTime(); 1.1 取当前年月日时分秒 currentTime=System.D ...

  7. zabbix告警时间和恢复时间相同的解决方法

    出现原因:在动作,恢复操作中,恢复时间成了{EVENT.DATE} {EVENT.TIME},所以和告警时间相同. 解决方法:将{EVENT.DATE}{EVENT.TIME}改成{EVENT.DAT ...

  8. C/C++程序基础 (六)面向对象

    类的特性 抽象.封装.继承.多态.重载 class 和 struct 区别 C中struct仅仅可以包含数据成员,不可以有成员函数,属于复杂数据结构. C++ 中struct成员访问权限默认为publ ...

  9. awk截取指定字段

    #!/bin/bash #好多地方可以优化,先记录下,便于以后使用 dir="/logs/$1"file="/logs/$1/requests.log"if [ ...

  10. [Poj2761]Feed the dogs(主席树)

    Desciption 题意:求区间第K小(N<=100000) Solution 主席树模板题 Code #include <cstdio> #include <algorit ...