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

先从基本的一些环境问题入手,梳理清楚关于手机设备和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. linux命令 ——目录

    开始详细系统的学习linux常用命令,坚持每天一个命令,所以这个系列为每天一个linux命令.学习的主要参考资料为: 1.<鸟哥的linux私房菜> 2.http://codingstan ...

  2. IOS 隐式动画(非Root Layer)

    ● 每一个UIView内部都默认关联着一个CALayer,我们可用称这个Layer为Root Layer(根 层) ● 所有的非Root Layer,也就是手动创建的CALayer对象,都存在着隐式动 ...

  3. 【洛谷2577】[ZJOI2005] 午餐(较水DP)

    点此看题面 大致题意: 有\(N\)个学生去食堂打饭,每个学生有两个属性:打饭时间\(a_i\)和吃饭时间\(b_i\).现要求将这些学生分成两队分别打饭,求最早何时所有人吃完饭. 贪心 首先,依据贪 ...

  4. js 实现纯前端将数据导出excel两种方式,亲测有效

    由于项目需要,需要在不调用后台接口的情况下,将json数据导出到excel表格,兼容chrome没问题,其他还没有测试过 通过将json遍历进行字符串拼接,将字符串输出到csv文件,输出的文件不会再是 ...

  5. java中 二进制 八进制 十六进制 十进制 相互转换 最简方法

    package com.swift; import java.util.Scanner; public class Hex2Decimal { public static void main(Stri ...

  6. vue学习之路 - 1.初步感知

    一.安装 这里使用node的npm包管理工具进行操作.操作前请先下载node. 在工程文件夹中使用以下命令安装vue: npm install vue 如下图所示:我在 helloworld 文件夹中 ...

  7. 洛谷 P1346 电车

    这道题的关键在建图 把每一个车站看成一个点,将这个车站相连的第一个车站建立一条边权为0的边,对于它所相连的其他车站,建立边权为1的边: 这样我们可以得到一张图: 起点,终点都知道了,跑一边最短路即可 ...

  8. TCP/IP与OSI参考模型原理

    网络是很重要同时也是很难理解的知识,这篇文章将会用自己容易理解的方式来记录有关网络的tcp与osi模型内容,不求专业深刻,但求通俗易懂也好. OSI参考模型 OSI定义了网络互连的七层框架(物理层.数 ...

  9. 课时5.什么是URL(理解)

    其实浏览器的地址栏中输入的地址就是一个URL. http://127.0.0.1/index.html(浏览器会自动添加:80) http://127.0.0.1:80/index.html(这是浏览 ...

  10. ZendFramework-2.4 源代码 - 关于MVC - Model层类图