有关什么是Coded UI Test以及如何使用Coded UI Test可以查看我的另一篇文章:http://www.cnblogs.com/jaxu/p/3706652.html

  本文主要介绍如何在Coded UI Test中使用数据驱动测试。考虑这样一个场景:开发人员提交了一个函数,该函数实现了一个数学公式的运算,通过接收两个数字并进行数学运算给出结果。测试人员根据给定的数学公式,需要考虑提供各种不同情况的值来循环测试该函数。显然,我们需要提供一个数据源,根据数据源中提供的不同的值来进行自动化测试。这是最常见的数据驱动测试的案例。在基于Coded UI Test的Webpage自动化测试中,浏览器兼容性问题是通常要考虑的,我们可以在数据源(数据源可能是一个记事本或者一个简单的Excel表格)中提供要测试的浏览器的名称和版本号,然后让Coded UI Test自动加载不同的浏览器来循环测试目标页面。下面的内容会介绍这些方法。

  这里有两篇文章详细描述了如何通过[DataSource]特征属性来完成数据驱动Coded UI Test。其基本思想是通过在TestMethod前面添加[DataSource]特征属性,并指定数据源的类型和位置,然后Coded UI Test的测试方法在运行时会自动读取数据源中的数据,在迭代中完成比对。

http://blogs.msdn.com/b/mathew_aniyan/archive/2009/03/17/data-driving-coded-ui-tests.aspx

http://msdn.microsoft.com/en-us/library/ms182527.aspx

  下面这段代码说明了这一情况:

[TestMethod]
[DataSource("System.Data.Odbc", @"Dsn=Excel Files;dbq=C:\Box Office Results.xlsx;defaultdir=C:;driverid=1046;maxbuffersize=2048;pagetimeout=5", "BoxOfficeResults$", DataAccessMethod.Sequential)]
public void MyTest()
{int rowIndex = this.TestContext.DataRow.Table.Rows.IndexOf(this.TestContext.DataRow);string s = this.TestContext.DataRow[0].ToString();
}

  特征属性[DataSource]有多个重载,以用来通过不同的方式指定数据源的位置。如果你不知道上述代码中的数据源连接字符串是如何提供的,可以在Visual Studio中尝试添加数据源操作,然后拷贝其中自动生成的数据源连接字符串。

  1. 在Visual Studio中通过VIEW->Other Windows->Data Sources打开数据源窗口
  2. 点击添加一个新的数据源,选择Database
  3. 点击New Connection...在打开的窗口中通过ODBC方式选择Excel文件,Visual Studio会自动为你生成连接字符串
  4. 拷贝该连接字符串

  运行上面的代码,你会发现其实数据读取工作是在迭代中完成的。也就是说测试方法会被不断地迭代,直到数据源中所有行均被读取完成。数据迭代的方式可通过枚举DataAccessMethod来指定,一共两种方式:顺序读取或随机读取。

  我们将上面代码中的Excel文件放到C盘根目录,然后调试代码。Excel中的第一行默认会被作为标题,数据默认会从第二行开始读取,所以第一次迭代的时候DataRow[0]返回的是Excel中A2单元格的内容。TestContext对象被作为数据源上下文,通过它你可以找到数据源的一些属性。例如通过上面代码中的第一行获取到数据源的行索引。这里是msdn上有关DataRow属性的说明http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.testcontext.datarow.aspx

  将数据源连接字符串直接写在代码里并不是什么明智之举,那有没有什么方法可以将它移到配置文件中呢?答案是肯定的!通过msdn的这篇文章我们可以得知如何将数据源连接字符串移到配置文件中http://msdn.microsoft.com/en-us/library/ms243192.aspx

  首先在工程中添加Application Configuration File,即App.config。

  内容如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration><configSections><section name="microsoft.visualstudio.testtools" type="Microsoft.VisualStudio.TestTools.UnitTesting.TestConfigurationSection, Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/></configSections><connectionStrings><add name="MyExcelConn" providerName="System.Data.Odbc" connectionString="Dsn=Excel Files;dbq=C:\Box Office Results.xlsx;defaultdir=C:;driverid=1046;maxbuffersize=2048;pagetimeout=5"/></connectionStrings><microsoft.visualstudio.testtools><dataSources><add name="BoxOfficeResults" connectionString="MyExcelConn" dataTableName="BoxOfficeResults$" dataAccessMethod="Sequential"/></dataSources></microsoft.visualstudio.testtools>
</configuration>

  注意microsoft.visualstudio.testtools节中type属性的版本号可能会由于使用的.NET Framework版本的不同有所变化。2.0为8.0.0.0,3.5为9.0.0.0,3.5以上应该是10.0.0.0。在App.config文件中添加上述配置信息之后,将测试方法的[DataSource]特征属性改成

[DataSource("BoxOfficeResults")]

  如果Excel文件中存在多个表,则可以在配置文件的<dataSources>中添加多个<add>节点,指明不同的数据表名称和数据读取方式。

  还记得文章一开始提到的使用数据驱动测试来实现多浏览器兼容性测试吗?我们可以通过下面的代码来实现。

BrowserWindow.CurrentBrowser = this.TestContext.DataRow[0].ToString();

  将不同版本的浏览器名称添加到数据源文件中,可以是一个简单的记事本或者.csv文件,如:

BrowserType
IE
firefox
chrome

  注意第一行是标题,[DataSource]特征属性在读取数据时始终会将第一行默认为标题行,数据默认是从第二行开始读取的。浏览器只需要提供名称即可,大小写没有关系。如果你的测试方法需要在不同的浏览器中完成测试,则可以尝试该方法,但我不保证其中是否会涉及到兼容性问题,就像我在前一篇文章中提到的Coded UI Test如何在页面上搜索一个控件,如果搜索的条件存在浏览器兼容性问题,则可能会抛出异常。

  虽然通过[DataSource]特征属性可以非常方便地读取数据源中的数据来完成数据驱动测试,但是有些情况下这种方式并不适用。考虑一个简单的需求:被测试页面上有一个表格,其数据来源于服务器上的一个Excel文件。通过编写基于数据驱动测试的Coded UI Test方法来检查页面上显示的内容是否与Excel文件一致。

  由于[DataSource]特征属性是以迭代的方式来进行数据驱动测试的,因此我们无法在数据迭代的过程中去遍历页面UI元素。况且,如果迭代中存在Assert断言,也不太方便我们输出测试结果。最终的期望是,遍历整个UI Table,通过与预先读取的数据源中的数据进行逐一比对来完成整个测试,其过程可能是这样:

  1. 读取数据源中的数据并缓存。由于无法使用[DataSource]特征属性自动读取数据,因此不得不自己编写代码来完成数据读取操作。
  2. 找到UI Table进行遍历,将所有单元格的数据缓存。
  3. 将两部分缓存的数据进行比对,这可能需要预先提供Mapping以帮助完成数据比对过程。

  我们以http://www.cnblogs.com/jaxu/p/3635634.html页面中的表格为例来看看如何实现这一过程。

  下面是UIMap2.uitest中的完整代码:

public partial class UIMap2
{public void LaunchPage(){this.UIExcelInteractiveViewWindow.LaunchUrl(new Uri("http://www.cnblogs.com/jaxu/p/3635634.html"));}public void TestTableData(){HtmlTable targetTable = this.UIExcelInteractiveViewWindow.UIExcelInteractiveViewDocument.UICnblogs_post_bodyPane.UIItemTable;HtmlRow rowall = new HtmlRow(targetTable);UITestControlCollection rows = rowall.FindMatchingControls();Dictionary<int, Dictionary<int, string>> PageTableDataCache = new Dictionary<int, Dictionary<int, string>>();int rowCount = rows.Count;for (int i = 0; i < rowCount; i++){HtmlCell allTD = new HtmlCell(rows[i]);UITestControlCollection TDs = allTD.FindMatchingControls();Dictionary<int, string> cellsDictionary = new Dictionary<int, string>();int tdCount = TDs.Count;for (int j = 0; j < tdCount; j++){cellsDictionary.Add(j, ((HtmlCell)TDs[j]).InnerText);}PageTableDataCache.Add(i, cellsDictionary);}Dictionary<int, Dictionary<int, string>> ExcelDataCache = GetExcelData(ConfigurationManager.AppSettings["ExcelPath"], "BoxOfficeResults");// load mappingMappingRow[] mappingRows = GetMappingRowCollection();string msg = string.Empty;for (int i = 0; i < mappingRows.Length; i++){Dictionary<int, string> pageRowCellsDictionary = PageTableDataCache[mappingRows[i].PageTableTrIndex];Dictionary<int, string> excelRowCellsDictionary = ExcelDataCache[mappingRows[i].ExcelRowNum];MappingColumn[] mappingColumns = mappingRows[i].MappingColumn;for (int j = 0; j < mappingColumns.Length; j++){string excelValue = excelRowCellsDictionary[mappingColumns[j].ExcelColumnNum];string pageValue = pageRowCellsDictionary[mappingColumns[j].PageTableTdIndex];Assert.AreEqual(excelValue, pageValue, string.Format("Validation failed at row {0} column {1}", mappingRows[i].ExcelRowNum, mappingColumns[j].ExcelColumnNum));}}}private Dictionary<int, Dictionary<int, string>> GetExcelData(string filePath, string sheetName){Dictionary<int, Dictionary<int, string>> sheetDataDic = new Dictionary<int, Dictionary<int, string>>();Application excel = new Application();excel.Visible = false;excel.UserControl = true;try{Workbook wb = (Workbook)excel.Application.Workbooks.Open(filePath,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value);foreach (var worksheet in wb.Worksheets){Worksheet ws = ((Worksheet)worksheet);if (ws.Name.Equals(sheetName)){int rowscount = ws.UsedRange.Cells.Rows.Count;int colscount = ws.UsedRange.Cells.Columns.Count;for (int i = 0; i < rowscount; i++){Dictionary<int, string> cellsDictionary = new Dictionary<int, string>();for (int j = 0; j < colscount; j++){Range range = ws.Cells.get_Range(ConvertNumberToName(j) + (i + 1));string cellText = ((object)range.Text) == null ? "" : ((object)range.Text).ToString();cellsDictionary.Add(j, cellText);}sheetDataDic.Add(i, cellsDictionary);}break;}}}finally{excel.Application.Workbooks.Close();excel.Quit();System.Runtime.InteropServices.Marshal.ReleaseComObject(excel);excel = null;GC.Collect();}return sheetDataDic;}private string ConvertNumberToName(int index){if (index < 0) { throw new Exception("invalid parameter"); }List<string> chars = new List<string>();do{if (chars.Count > 0) index--;chars.Insert(0, ((char)(index % 26 + (int)'A')).ToString());index = (int)((index - index % 26) / 26);} while (index > 0);return String.Join(string.Empty, chars.ToArray());}private MappingRow[] GetMappingRowCollection(){Mapping mapping = null;MappingRow[] mappingRowCollection = null;XmlSerializer serializer = new XmlSerializer(typeof(Mapping));using (FileStream fs = new FileStream(ConfigurationManager.AppSettings["MappingsPath"], FileMode.Open)){using (XmlReader reader = XmlReader.Create(fs)){mapping = (Mapping)serializer.Deserialize(reader);}}if (mapping != null){mappingRowCollection = mapping.MappingRow;}return mappingRowCollection;}
}

  其中有两个public方法:LaunchPage()用来导航到目标页面;TestTableData()用来遍历目标页面上的表格并与数据源Excel中的数据进行比对,给出测试结果。

  私有方法GetExcelData()用来读取Excel文件中的数据,其中用到了Microsoft.Office.Interop.Excel程序集中的对象,需要在工程中单独添加引用。数据按行和列的方式存放到Dicitionary字典对象中,字典中的Key为每一行的行号,Value则是另一个字典,包含该行所有的列。事实上,程序中的其它地方也用到了这种数据存储结构。

  在TestTableData()方法中,一共完成了三个步骤:

  1. 首先遍历页面上的Table,将单元格的内容缓存到字典对象PageTableDataCache中。该字典对象的数据存储结构与上面讲到的Excel数据存储结构相同。值得注意的是,在遍历Table的过程中由于是遍历Table下面所有HtmlRow的集合,此处不包含Header部分,因此Table的表头部分的数据不会被存储到字典对象中。
  2. 通过GetExcelData()方法将Excel中的数据缓存到字典对象ExcelDataCache中。
  3. 添加一个Mapping,用来对页面上的表格和Excel进行映射。为什么需要Mapping?因为页面上表格中单元格的行和列与Excel中的行和列并不总是一一对应的,所以这里必须要通过Mapping来进行映射,以确定如何进行比对。Mapping可以是一个XML文件,在程序中通过反序列化的方式进行读取,该操作由私有方法GetMappingRowCollection()完成。下面是Mapping XML文件的内容,有关如何通过Visual Studio自动生成XML反序列化的类,可以查看这篇文章http://www.cnblogs.com/jaxu/p/3632077.html。
    <?xml version="1.0" encoding="utf-8" ?>
    <Mapping><MappingRow ExcelRowNum="1" PageTableTrIndex="0"><MappingColumn ExcelColumnNum="0" PageTableTdIndex="0"/><MappingColumn ExcelColumnNum="1" PageTableTdIndex="1"/><MappingColumn ExcelColumnNum="2" PageTableTdIndex="2"/><MappingColumn ExcelColumnNum="3" PageTableTdIndex="3"/><MappingColumn ExcelColumnNum="4" PageTableTdIndex="4"/></MappingRow><MappingRow ExcelRowNum="2" PageTableTrIndex="1"><MappingColumn ExcelColumnNum="0" PageTableTdIndex="0"/><MappingColumn ExcelColumnNum="1" PageTableTdIndex="1"/><MappingColumn ExcelColumnNum="2" PageTableTdIndex="2"/><MappingColumn ExcelColumnNum="3" PageTableTdIndex="3"/><MappingColumn ExcelColumnNum="4" PageTableTdIndex="4"/></MappingRow><MappingRow ExcelRowNum="3" PageTableTrIndex="2"><MappingColumn ExcelColumnNum="0" PageTableTdIndex="0"/><MappingColumn ExcelColumnNum="1" PageTableTdIndex="1"/><MappingColumn ExcelColumnNum="2" PageTableTdIndex="2"/><MappingColumn ExcelColumnNum="3" PageTableTdIndex="3"/><MappingColumn ExcelColumnNum="4" PageTableTdIndex="4"/></MappingRow><MappingRow ExcelRowNum="4" PageTableTrIndex="3"><MappingColumn ExcelColumnNum="0" PageTableTdIndex="0"/><MappingColumn ExcelColumnNum="1" PageTableTdIndex="1"/><MappingColumn ExcelColumnNum="2" PageTableTdIndex="2"/><MappingColumn ExcelColumnNum="3" PageTableTdIndex="3"/><MappingColumn ExcelColumnNum="4" PageTableTdIndex="4"/></MappingRow><MappingRow ExcelRowNum="5" PageTableTrIndex="4"><MappingColumn ExcelColumnNum="0" PageTableTdIndex="0"/><MappingColumn ExcelColumnNum="1" PageTableTdIndex="1"/><MappingColumn ExcelColumnNum="2" PageTableTdIndex="2"/><MappingColumn ExcelColumnNum="3" PageTableTdIndex="3"/><MappingColumn ExcelColumnNum="4" PageTableTdIndex="4"/></MappingRow><MappingRow ExcelRowNum="6" PageTableTrIndex="5"><MappingColumn ExcelColumnNum="0" PageTableTdIndex="0"/><MappingColumn ExcelColumnNum="1" PageTableTdIndex="1"/><MappingColumn ExcelColumnNum="2" PageTableTdIndex="2"/><MappingColumn ExcelColumnNum="3" PageTableTdIndex="3"/><MappingColumn ExcelColumnNum="4" PageTableTdIndex="4"/></MappingRow><MappingRow ExcelRowNum="7" PageTableTrIndex="6"><MappingColumn ExcelColumnNum="0" PageTableTdIndex="0"/><MappingColumn ExcelColumnNum="1" PageTableTdIndex="1"/><MappingColumn ExcelColumnNum="2" PageTableTdIndex="2"/><MappingColumn ExcelColumnNum="3" PageTableTdIndex="3"/><MappingColumn ExcelColumnNum="4" PageTableTdIndex="4"/></MappingRow><MappingRow ExcelRowNum="8" PageTableTrIndex="7"><MappingColumn ExcelColumnNum="0" PageTableTdIndex="0"/><MappingColumn ExcelColumnNum="1" PageTableTdIndex="1"/><MappingColumn ExcelColumnNum="2" PageTableTdIndex="2"/><MappingColumn ExcelColumnNum="3" PageTableTdIndex="3"/><MappingColumn ExcelColumnNum="4" PageTableTdIndex="4"/></MappingRow><MappingRow ExcelRowNum="9" PageTableTrIndex="8"><MappingColumn ExcelColumnNum="0" PageTableTdIndex="0"/><MappingColumn ExcelColumnNum="1" PageTableTdIndex="1"/><MappingColumn ExcelColumnNum="2" PageTableTdIndex="2"/><MappingColumn ExcelColumnNum="3" PageTableTdIndex="3"/><MappingColumn ExcelColumnNum="4" PageTableTdIndex="4"/></MappingRow><MappingRow ExcelRowNum="10" PageTableTrIndex="9"><MappingColumn ExcelColumnNum="0" PageTableTdIndex="0"/><MappingColumn ExcelColumnNum="1" PageTableTdIndex="1"/><MappingColumn ExcelColumnNum="2" PageTableTdIndex="2"/><MappingColumn ExcelColumnNum="3" PageTableTdIndex="3"/><MappingColumn ExcelColumnNum="4" PageTableTdIndex="4"/></MappingRow>
    </Mapping>

    同时,由于程序中需要读取Excel文件以及反序列化Mapping XML文件,需要在App.config文件中添加两个配置项。

    <appSettings><add key="MappingsPath" value="..\..\..\CodedUITestProject2\Mapping.xml"/><add key="ExcelPath" value="c:\Box Office Results.xlsx"/>
    </appSettings>

    注意MappingPath的路径使用的是相对路径,通过将该文件设置为拷贝到输出路径以方便部署。方法是在Visual Studio的Solution Explorer中右键选择该文件->Properties,将Copy to Output Directory改成Copy always。

  4. 遍历Mapping中所有行和列,并比较PageTable和Excel中的数据,通过Assert断言来获取测试结果。由于Assert断言在测试失败时总会抛出异常而终止余下的测试步骤,可以参考文章http://www.cnblogs.com/jaxu/p/3706652.html中有关Assert断言部分对上述代码进行改进。
  5. 添加测试方法以调用LaunchPage()和TestTableData()
    [TestMethod]
    public void MyTest()
    {UIMap2 uimap = new UIMap2();uimap.LaunchPage();uimap.TestTableData();
    }

  下面的代码由Visual Studio自动生成并做了少量修改(将byte类型改为int),用来将Mapping XML进行反序列化。

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class Mapping
{private MappingRow[] mappingRowField;/// <remarks/>[System.Xml.Serialization.XmlElementAttribute("MappingRow")]public MappingRow[] MappingRow{get{return this.mappingRowField;}set{this.mappingRowField = value;}}
}/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class MappingRow
{private MappingColumn[] mappingColumnField;private int excelRowNumField;private int pageTableTrIndexField;/// <remarks/>[System.Xml.Serialization.XmlElementAttribute("MappingColumn")]public MappingColumn[] MappingColumn{get{return this.mappingColumnField;}set{this.mappingColumnField = value;}}/// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]public int ExcelRowNum{get{return this.excelRowNumField;}set{this.excelRowNumField = value;}}/// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]public int PageTableTrIndex{get{return this.pageTableTrIndexField;}set{this.pageTableTrIndexField = value;}}
}/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class MappingColumn
{private int excelColumnNumField;private int pageTableTdIndexField;/// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]public int ExcelColumnNum{get{return this.excelColumnNumField;}set{this.excelColumnNumField = value;}}/// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]public int PageTableTdIndex{get{return this.pageTableTdIndexField;}set{this.pageTableTdIndexField = value;}}
}

  UIMap2.uitest中的代码实现了Excel数据与页面Table中的内容比对,并最终通过了测试。不过从严格意义上来讲,这种情况应该不属于数据驱动测试的范畴,数据驱动测试的意义在于通过给定的数据来测试程序已有的功能,而上述情况是通过数据源来比对UI中的内容。不过我们仍然可以从中了解到如何编写代码来读取数据源并对Webpage中的表格进行Coded UI test。

转载于:https://www.cnblogs.com/jaxu/p/3710672.html

Coded UI Test中的数据驱动测试相关推荐

  1. Unittest自动化测试框架教程(四)——Python中的数据驱动测试DDT

     " 数据驱动测试DDT(Data Drivern test),是自动化测试领域优势中亮眼的闪光点,在unittest测试框架中对数据驱动更是提供了强大的支持,文章通过基础概念的引入,介绍了 ...

  2. 在Visual Studio 2010中实现数据驱动Coded UI Tests

    通常情况下,我们要与不同的数据值一起重复一个测试.这个"数据驱动"在Coded UI Test中非常容易的.在本例子中,我们创建了一个Coded UI Test,以验证在计算器的两 ...

  3. 如何使用Coded UI Test对Webpage进行自动化测试

    在Visual Studio中,Coded UI Test已经不是什么新特性了,较早版本的Visual Studio中就已经有这个东东了.它主要用来帮助自动化测试工程师和开发人员确保程序在UI方面没有 ...

  4. 测试:VS2010的Coded UI Test参考内容列表

    本篇是一个内容索引,对测试不感兴趣的可以马上飘过:)前几篇IronRuby的文章都是围绕着自动化测试来写的,这个测试框架使用了微软的CodedUI Test的几个dll功能来写的.学习任何新的技术和事 ...

  5. VS 2010 测试功能学习(八) - RnP与Coded UI测试(继续篇)

    题外话:CSDN博客不能上传图 片已经有一周多了,以前的博客内容中的图片仍然是"图片审核中..."状态,没关系,咱是中国网民,咱最大的优点就是能忍!图片不能传,咱继续发文字内容 的 ...

  6. VS 2010 测试功能学习(七) - RnP与Coded UI自动化测试

      题外话:昨天去上海浦东机场接闺女, 一切还是蛮顺利的,公交机场7线直接从上海火车南站一站直达浦东机场,票价20元,算上乘坐地铁5号和1号线的6元,从我家到机场总共要26元,相对于打 的士的220元 ...

  7. RobotFramework自动化框架—数据驱动测试

    前情介绍: 在自动化测试框架中,数据驱动的意思是指定的是测试用例或者说测试套件是由外部数据集合来驱动的框架. 数据集合(也可称之为数据来源)可以是任何类型的数据文件比如xls,xlsx,csv等等,甚 ...

  8. junit数据驱动测试_使用Junit和Easytest进行数据驱动的测试

    junit数据驱动测试 在本文中,我们将看到如何使用Junit进行数据驱动的测试. 为此,我将使用一个名为EasyTest的库. 我们知道,对于TestNG,它已内置了数据提供程序. 通过简单的测试, ...

  9. python数据驱动测试设计_GitHub - 13691579846/DataDriverTestFrameWork: python+selenium+pageobject数据驱动测试框架...

    DataDriverTestFrameWork 一.说明 ``本实例为数据驱动测试框架搭建实践`` 二.框架分析 注意!注意!注意!重要的示请说3遍,本项目只用于学习使用,为了你能够成功执行本项目 e ...

最新文章

  1. 【论文】ICLR 2020 九篇满分论文!!!
  2. [转] 前端数据驱动的价值
  3. 矩阵运算最快的库有哪些
  4. 查oracle事务超时时间,ORA-24756: 事务处理不存在 分析
  5. 理解JavaScript中的原型继承(2)
  6. 【Python学习】 - pyecharts包 - 地图可视化
  7. 5分钟带你看懂 GCanvas渲染引擎的演进
  8. 借助datetime和pyttsx3在Python中创建闹钟
  9. 初学者python笔记(文件的操作)
  10. Pandas timedelta_range
  11. JPA 单元测试配置
  12. LNMP详解(十一)——Nginx URL重写原理
  13. python查询ip归属地,Python查询IP地址归属完整代码
  14. wps如何自己制作流程图_WPS如何绘制流程图? WPS绘图流程图详细教程
  15. 【辅助开发】游戏辅助开发全流程-golang
  16. 决赛巅峰之战落幕,第二届翼支付杯大数据建模大赛完美收官
  17. java 判断对象中所有属性都为空
  18. web开发前台,懒人建站资源库
  19. EXCEL学生成绩里计算年级名次、班级名次
  20. 在外文paper写作中,英文杂志以及英文会议缩写名称怎么查找

热门文章

  1. bowtie 加mn标签_Bowtie2使用方法与参数详细介绍
  2. WZOI-202去除圆括号
  3. 【C++构造函数后面的冒号作用】
  4. 西少爷肉夹馍:小摊上的秘密
  5. Tensorflow学习五---全连接
  6. ClickHouse全连接
  7. windows server 2012 服务器nacos 安装配置以及集群搭建
  8. HTML单选框美化和动效插件
  9. idea新建项目报错org.codehaus.plexus.component.repository.exception.ComponentLookupException:
  10. 安防智能视频平台EasyNVR无法接入EasyNVS并报错Login error的排查与解决