我有一个使用 StreamReader 的方法,我想对其进行单元测试。我将 StreamReader 的创建拆分为一个单独的类并尝试模拟该类,但我的单元测试仍然给我错误。
用于抽象 StreamReader 的类/接口
public interface IPathReader
{
TextReader CreateReader(string path);
}
public class PathReader : IPathReader
{
public TextReader CreateReader(string filePath)
{
return new StreamReader(filePath);
}
}
包含 GetLastRowInFile 的类(我试图进行单元测试的方法)。
public interface IIOManager
{
int GetLastRowInFile(string filePath, List<String> errorMessageList);
}
public class IOManager : IIOManager
{
private IPathReader _reader;
public IOManager(IPathReader reader)
{
this._reader = reader;
}
//...
public int GetLastRowInFile(string filePath, List<String> errorMessage)
{
int numberOfRows = 0;
string dataRow;
try
{
using (StreamReader rowReader = (StreamReader)_reader.CreateReader(filePath))
{
while ((rowReader.Peek()) > -1)
{
dataRow = rowReader.ReadLine();
numberOfRows++;
}
return numberOfRows;
}
}
catch (Exception ex)
{
errorMessage.Add(ex.Message);
return -1;
}
}
}
StreamReader 不包含默认构造函数,所以我不相信我可以直接模拟它,因此需要从 GetLastRowInFile 中创建 StreamReader。
问题
- CreateReader 的返回类型应该是 TextReader 吗?
- 在将返回的 TextReader 分配给 rowReader 之前,我是否需要将其显式转换回 StringReader?
- 当我创建 IPathReader 接口的模拟并将 CreateReader 设置为返回 StringReader 时,当它被分配给 rowReader 时会发生什么。我认为不可能在相同的继承级别上投射一些东西?
单元测试如下,它一直返回-1
[Test]
public void GetLastRowInFile_ReturnsNumberOfRows_Returns3()
{
string testString = "first Row" + Environment.NewLine + "second Line" + Environment.NewLine + "Third line";
List<String> errorMessageList = new List<string>();
Mock<IPathReader> mock = new Mock<IPathReader>();
mock.Setup(x => x.CreateReader(It.IsAny<string>())).Returns(new StringReader(testString));
IOManager testObject = new IOManager(mock.Object);
int i = testObject.GetLastRowInFile(testString, errorMessageList); //Replace with It.IsAny<string>()
Assert.AreEqual(i, 3);
Assert.AreEqual(errorMessageList.Count, 0);
}
我假设我缺少一些基本的东西,所以我真的很感谢你的帮助。谢谢你的时间。
编辑
测试方法:
public void GetLastRowInFile_ReturnsNumberOfRows_Returns3()
{
StubGetLastRowInFile myStub = new StubGetLastRowInFile();
List<String> errorMessageList = new List<string>();
IOManager testObject = new IOManager(myStub);
int i = testObject.GetLastRowInFile(It.IsAny<string>(), errorMessageList);
Assert.AreEqual(i, 3);
Assert.AreEqual(errorMessageList.Count, 0);
}
存根声明:
public class StubGetLastRowInFile : IPathReader
{
public TextReader CreateReader(string path)
{
//string testString = "first Row" + Environment.NewLine + "second Line" + Environment.NewLine + "Third line";
string testString = "04/01/2010 00:00,1.4314,1.4316";
UTF8Encoding encoding = new UTF8Encoding();
UnicodeEncoding uniEncoding = new UnicodeEncoding();
byte[] testArray = encoding.GetBytes(testString);
MemoryStream ms = new MemoryStream(testArray);
StreamReader sr = new StreamReader(ms);
return sr;
}
}
编辑 2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Data;
using System.Globalization;
using System.Collections;
using System.Reflection;
using System.ComponentModel;
namespace FrazerMann.CsvImporter.Entity
{
public interface IPathReader
{
TextReader CreateReader(string path);
}
public class PathReader : IPathReader
{
public TextReader CreateReader(string filePath)
{
return new StreamReader(filePath);
}
}
public interface IIOManager
{
Stream OpenFile(string path);
int GetLastRowInFile(string filePath, List<String> errorMessageList);
int GetNumberOfColumnsInFile(string filePath, List<string> errorMessageList);
bool IsReadOnly(string filePath);
}
public class IOManager : IIOManager
{
private IPathReader _reader;
public IOManager(IPathReader reader)
{
this._reader = reader;
}
public Stream OpenFile(string path)
{
return new FileStream(path, FileMode.Open);
}
public int GetNumberOfColumnsInFile(string filePath, List<String> errorMessageList)
{
int numberOfColumns = 0;
string lineElements;
try
{
using (StreamReader columnReader = (StreamReader)_reader.CreateReader(filePath))
{
lineElements = columnReader.ReadLine();
string[] columns = lineElements.Split(',');
numberOfColumns = columns.Length;
}
}
catch (Exception ex)
{
errorMessageList.Add(ex.Message);
numberOfColumns = -1;
}
return numberOfColumns;
}
public int GetLastRowInFile(string filePath, List<String> errorMessage)
{
int numberOfRows = 0;
string dataRow;
try
{
using (StreamReader rowReader = (StreamReader)_reader.CreateReader(filePath))
{
while ((rowReader.Peek()) > -1)
{
dataRow = rowReader.ReadLine();
numberOfRows++;
}
return numberOfRows;
}
}
catch (Exception ex)
{
errorMessage.Add(ex.Message);
return -1;
}
}
public bool IsReadOnly(string filePath)
{
FileInfo fi = new FileInfo(filePath);
return fi.IsReadOnly;
}
}
public interface IVerificationManager
{
void ValidateCorrectExtension(string filePath, List<String> errorMessageList);
void ValidateAccessToFile(string filePath, List<String> errorMessageList);
void ValidateNumberOfColumns(string filePath, int dataTypeCount, List<String> errorMessageList);
int ValidateFinalRow(int finalRow, string filePath, List<String> errorMessageList);
void ValidateRowInputOrder(int initialRow, int finalRow, List<String> errorMessageList);
void EnumeratedDataTypes(UserInputEntity inputs, List<String> errorMessageList);
int GetProgressBarIntervalsForDataVerification(int initialRow, int finalRow, List<String> errorMessageList);
}
public class VerificationManager : IVerificationManager
{
private IIOManager _iomgr;
public VerificationManager(IIOManager ioManager)
{
this._iomgr = ioManager;
}
public void ValidateCorrectExtension(string filePath, List<String> errorMessageList)
{
if (filePath.EndsWith(".txt", StringComparison.OrdinalIgnoreCase) | filePath.EndsWith(".csv", StringComparison.OrdinalIgnoreCase)) { }
else
{
errorMessageList.Add("Selected file does not have a compatable extension.");
}
}
public void ValidateAccessToFile(string filePath, List<String> errorMessageList)
{
try
{
if (_iomgr.IsReadOnly(filePath) == true) { }
else
{
errorMessageList.Add("Can not read/write to the specified file.");
}
}
catch (Exception e)
{
errorMessageList.Add(e.Message);
}
}
public void ValidateNumberOfColumns(string filePath, int userSpecifiedColumnCount, List<String> errorMessageList)
{
int numberOfColumnsInFile = _iomgr.GetNumberOfColumnsInFile(filePath, errorMessageList);
if (userSpecifiedColumnCount != numberOfColumnsInFile) errorMessageList.Add("Number of columns specified does not match number present in file.");
}
//**TEST APPLIES HERE**
public int ValidateFinalRow(int finalRow, string filePath, List<String> errorMessageList)
{
int totalNumberOfRowsInFile = 0;
totalNumberOfRowsInFile = _iomgr.GetLastRowInFile(filePath, errorMessageList);
if (totalNumberOfRowsInFile != -1)
{
if (finalRow == 0)
{
return totalNumberOfRowsInFile;
}
else
{
if (finalRow > totalNumberOfRowsInFile)
{
errorMessageList.Add("Specified 'Final Row' value is greater than the total number of rows in the file.");
}
}
}
return 0;
}
public void ValidateRowInputOrder(int initialRow, int finalRow, List<String> errorMessageList)
{
if (initialRow > finalRow)
{
errorMessageList.Add("Initial row is greater than the final row.");
}
}
public void EnumeratedDataTypes(UserInputEntity inputs, List<String> errorMessageList)
{
inputs.EnumeratedDataTypes = new int[inputs.DataTypes.Count];
try
{
for (int i = 0; i < inputs.DataTypes.Count; i++)
{
inputs.EnumeratedDataTypes[i] = (int)Enum.Parse(typeof(Enumerations.ColumnDataTypes), inputs.DataTypes[i].ToUpper());
}
}
catch (Exception ex)
{
errorMessageList.Add(ex.Message);
}
}
public int GetProgressBarIntervalsForDataVerification(int initialRow, int finalRow, List<String> errorMessageList)
{
int progressBarUpdateInverval = -1;
try
{
int dif = (finalRow - initialRow) + 1;
progressBarUpdateInverval = dif / 100;
if (progressBarUpdateInverval == 0)
{
progressBarUpdateInverval = 1;
}
}
catch (Exception ex)
{
errorMessageList.Add(ex.Message);
}
return progressBarUpdateInverval;
}
}
public class EntityVerification
{
private VerificationManager _vmgr;
public EntityVerification(VerificationManager vManager)
{
this._vmgr = vManager;
}
public void VerifyUserInputManager(UserInputEntity inputs, List<string> errorMessageList)
{
_vmgr.ValidateCorrectExtension(inputs.CsvFilePath ,errorMessageList);
_vmgr.ValidateCorrectExtension(inputs.ErrorLogFilePath, errorMessageList);
_vmgr.ValidateAccessToFile(inputs.CsvFilePath, errorMessageList);
_vmgr.ValidateAccessToFile(inputs.ErrorLogFilePath, errorMessageList);
_vmgr.ValidateNumberOfColumns(inputs.CsvFilePath, inputs.DataTypes.Count, errorMessageList);
inputs.FinalRow = _vmgr.ValidateFinalRow(inputs.FinalRow, inputs.CsvFilePath, errorMessageList);
_vmgr.ValidateRowInputOrder(inputs.InitialRow, inputs.FinalRow, errorMessageList);
_vmgr.EnumeratedDataTypes(inputs, errorMessageList);
inputs.ProgressBarUpdateIntervalForDataVerification = _vmgr.GetProgressBarIntervalsForDataVerification(inputs.InitialRow, inputs.FinalRow, errorMessageList);
}
}
}
测试方法(适用于 VerificationManager 类中倒数第三个方法)
[Test]
public void ValidateFinalRow_FinalRowReturned_Returns6()
{
List<String> errorMessageList = new List<string>(); //Remove if replaced
Mock<IIOManager> mock = new Mock<IIOManager>();
mock.Setup(x => x.GetLastRowInFile(It.IsAny<String>(), errorMessageList)).Returns(6);
VerificationManager testObject = new VerificationManager(mock.Object);
int i = testObject.ValidateFinalRow(0, "Random", errorMessageList); //Replace with It.IsAny<string>() and It.IsAny<List<string>>()
Assert.AreEqual(i, 6);
}