【问题标题】:Consecutively reading data from Excel in C#/NUnit test cases, returns blank data for 2nd Case在 C#/NUnit 测试用例中从 Excel 中连续读取数据,为 2nd Case 返回空白数据
【发布时间】:2020-04-17 12:10:59
【问题描述】:

我正在尝试编写一个执行两次的参数化 NUnit 测试。每次运行时,它都会引用电子表格中不同的 row,并根据 int rowNum 获取用户名和密码。

    class Test
    {
        //Run the test twice
        [Test,TestCase(1),TestCase(2)]
        public void T101_LoginTestSuite_Valid(int rowNum)
        {
            Console.WriteLine(TestContext.CurrentContext.Test.MethodName); //Test Name 
            Console.WriteLine("Row number "+rowNum);// Value of rowNum

            ExcelDataFactory.GetTestDataSet(TestContext.CurrentContext.Test.MethodName);

            //Print out the credentials
            Console.WriteLine(ExcelDataFactory.ReadData(rowNum,"username")); 
            Console.WriteLine(ExcelDataFactory.ReadData(rowNum, "password"));
        }
    }

这是excel

第一个测试用例正确获取用户名和密码。

但是第二个测试用例返回空白(如果我单独运行它会起作用!)

下面是ExcelDataFactory代码:

    class ExcelDataFactory
    {
        //Get data from excel
        private static DataTable ExcelToDataTable(String filename, String sheetName)
        {
            //Open file and returns as Stream
            FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read);

            //CreateOpenXmlReader via ExcelReaderFactory 
            IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream); //.xlsx

            //Return as DataSet and set the frist row as column name
            DataSet result = excelReader.AsDataSet(new ExcelDataSetConfiguration()
            {
                ConfigureDataTable = (_) => new ExcelDataTableConfiguration()
                {
                    UseHeaderRow = true
                }
            });

            DataTableCollection table = result.Tables;


            DataTable resultTable = table[sheetName];

            //Close FileStream
            stream.Close();

            //Return
            return resultTable; 
        }

        //Put data into a collection 
        static List<DataCollection> dataCollection = new List<DataCollection>();

        public static void PopulateInCollection(string fileName, String sheetName)
        {
            DataTable table = ExcelToDataTable(fileName,sheetName);

            //Iterate through the rows and columns of the Table
            for(int row = 1; row <= table.Rows.Count; row++)
            {
                for (int column = 0; column < table.Columns.Count; column++)
                {
                    DataCollection dataTable = new DataCollection()
                    {
                        rowNumber = row,
                        columnName = table.Columns[column].ColumnName,
                        columnValue = table.Rows[row - 1][column].ToString()
                    };
                    //Add all the details for each row
                    dataCollection.Add(dataTable);
                }
            }
        }

        //Find the correct excel file and sheet
        public static void GetTestDataSet(String testName)
        {
            String[] testNameSplit = testName.Split('_');
            String filePath = MyProps.Default.TestData //Add path
                    + testNameSplit[1]
                    + "."
                    + "xlsx";
            PopulateInCollection(filePath, testNameSplit[0]);
        }

        public static string ReadData(int rowNumber, string columnName)
        {
            try 
            {
                //Retriving Data using LINQ to reduce amount of iterations
                string data = (from collectionData in dataCollection
                               where collectionData.columnName == columnName && collectionData.rowNumber == rowNumber
                               select collectionData.columnValue).SingleOrDefault();

                //var data   = dataCollection.Where(collectionData => collectionData.columnName == columnName && collectionData.rowNumber == rowNumber).SingleOrDefault().columnValue; 
                return data.ToString();
            } 
            catch (Exception e)
            {
                e.StackTrace.ToString();
                return null;
            }
        }

    }  

    class DataCollection
    {
        public int rowNumber { get; set; }

        public string columnName { get; set; }

        public string columnValue { get; set; }
    }

我怀疑 ExcelDataFactory.GetTestDataSet 方法是在错误的地方调用的,但我真的很困惑为什么会这样。任何想法将不胜感激。

【问题讨论】:

  • 您将excel的数据存储在静态成员中?所以如果两件事调用同一个函数,你期望发生什么?您应该从函数调用中返回数据,而不是附加到某些会被多次调用污染的静态成员。
  • 好的,我应该返回一个 List dataCollection 的新实例,而不是静态的?
  • 是的,我想是的。你明白static 是什么意思吗?做一些研究可能是一件好事。我个人尽量避免静态,当我确实使用它们时,我会确保它们是确定性函数。

标签: c# nunit filestream exceldatareader


【解决方案1】:

我对 ExcelDataFactory 类做了一些快速更改,我删除了 static 引用,现在 PopulateInCollection 方法返回一个 List 在类开始时声明和初始化。

using ExcelDataReader;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Wizuda_Selenium_Test_Automation
{
    class ExcelDataFactory
    {
        List<DataCollection> dataCollection = new List<DataCollection>();

        private static DataTable ExcelToDataTable(String filename, String sheetName)
        {
            //Open file and returns as Stream
            FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read);

            //CreateOpenXmlReader via ExcelReaderFactory 
            IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream); //.xlsx

            //Return as DataSet and set the frist row as column name
            DataSet result = excelReader.AsDataSet(new ExcelDataSetConfiguration()
            {
                ConfigureDataTable = (_) => new ExcelDataTableConfiguration()
                {
                    UseHeaderRow = true
                }
            });

            DataTableCollection table = result.Tables;


            DataTable resultTable = table[sheetName];

            //Close FileStream
            stream.Close();

            //Return
            return resultTable; 
        }

        //static List<DataCollection> dataCollection = new List<DataCollection>();

        public List<DataCollection> PopulateInCollection(string fileName, String sheetName)
        {
            dataCollection = new List<DataCollection>();

            DataTable table = ExcelToDataTable(fileName,sheetName);

            //Iterate through the rows and columns of the Table
            for(int row = 1; row <= table.Rows.Count; row++)
            {
                for (int column = 0; column < table.Columns.Count; column++)
                {
                    DataCollection dataTable = new DataCollection()
                    {
                        rowNumber = row,
                        columnName = table.Columns[column].ColumnName,
                        columnValue = table.Rows[row - 1][column].ToString()
                    };

                    //Add all the details for each row
                    dataCollection.Add(dataTable);
                }
            }

            return dataCollection;
        }

        public string ReadData(int rowNumber, string columnName)
        {
            try 
            {
                //Retriving Data using LINQ to reduce amount of iterations
                string data = (from collectionData in dataCollection
                               where collectionData.columnName == columnName && collectionData.rowNumber == rowNumber
                               select collectionData.columnValue).SingleOrDefault();

                //var data   = dataCollection.Where(collectionData => collectionData.columnName == columnName && collectionData.rowNumber == rowNumber).SingleOrDefault().columnValue; 
                return data.ToString();
            } 
            catch (Exception e)
            {
                e.StackTrace.ToString();
                return null;
            }
        }

        public void GetTestDataSet(String testName)
        {
            String[] testNameSplit = testName.Split('_');
            String filePath = MyProps.Default.TestData //Add path
                    + testNameSplit[1] //LoginTestSuite
                    + "."
                    + "xlsx";              //T101
            PopulateInCollection(filePath, testNameSplit[0]);
        }
    }  

    class DataCollection
    {
        public int rowNumber { get; set; }

        public string columnName { get; set; }

        public string columnValue { get; set; }
    }
}

我更新了测试以创建 ExcelDataFactory 的新实例

        [Test,TestCase(1),TestCase(2)]
        public void T101_LoginTestSuite_Valid(int rowNum)
        {
            ExcelDataFactory excelDataFactory = new ExcelDataFactory();

            Console.WriteLine(TestContext.CurrentContext.Test.MethodName);
            Console.WriteLine("Row number "+rowNum);
            excelDataFactory.GetTestDataSet(TestContext.CurrentContext.Test.MethodName);

            Console.WriteLine("username= "+ excelDataFactory.ReadData(rowNum,"username"));
            Console.WriteLine("password= "+ excelDataFactory.ReadData(rowNum, "password"));
        }

现在测试通过了

我想我需要回去重新学习一下使用静态方法,谢谢Kritner

【讨论】:

  • 虽然你已经找到了解决方案,但是我想指出的是,你的两个案例的执行顺序是不能保证的。不确定这对您是否重要。
  • 此时这并不重要。我将尝试将每个测试自身包含在自己的方法中,以便它们彼此独立。但是,如果有一种方法可以在 C#/NUnit 或测试设计中定义测试顺序,我欢迎任何建议。
  • 一般来说,保持测试独立是最好的方法。对于订单很重要的罕见情况,NUnit 有一个 OrderAttribute。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-24
  • 2021-05-10
  • 1970-01-01
  • 2020-01-13
  • 2011-12-18
  • 1970-01-01
  • 2018-08-27
相关资源
最近更新 更多