2012-08-09 97 views
4

我有一个使用的StreamReader的方法,其我想单元测试。我把StreamReader的创建分成了一个单独的类,并试图嘲笑这个类,但是我的单元测试仍然给我错误。惩戒一个StreamReader

类/接口用于抽象含有GetLastRowInFile(方法即时试图单元测试)的StreamReader的

public interface IPathReader 
{ 
    TextReader CreateReader(string path); 
} 

public class PathReader : IPathReader 
{ 
    public TextReader CreateReader(string filePath) 
    { 
     return new StreamReader(filePath); 
    } 
} 

类。

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犯规包含一个默认的构造函数,所以我不认为我可以直接嘲笑它,因此需要采取的StreamReader的创造出GetLastRowInFile的。

问题

  1. 应该CreateReader的返回类型为TextReader的?
  2. 我是否需要将其分配给rowReader之前明确转换返回的TextReader回StringReader?
  3. 当我创建IPathReader接口的模拟效果和设立CreateReader返回一个StringReader替换,当它被分配到rowReader会发生什么。我认为不可能在相同的继承层次上施放某些东西?

Inheritance Hierarchy

单元测试如下:它不断地返回-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); 
    } 

林假设有最根本的是我在想念所以ID真的很感激一些帮助this.Thanks您时间。

编辑

测试方法:

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; 
    } 
} 

EDIT 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); 
    } 

回答

9

你为什么要在这里使用嘲讽目前尚不清楚。

是,使用TextReader,而不需要StreamReader会给你更多的灵活性。很少有情况下,它明确指定StreamReader作为参数或返回类型。

如果你想为StreamReader提供的测试数据,只需创建一个StreamReader包装一MemoryStream

当您返回StringReader,确实会导致异常时,它的投(或嘲弄的框架本身)。不幸的是,你的异常处理过于宽泛,所以很难看到这个问题。你catch块或许应该只有IOException - 如果确实什么。 (如果资源不能被读取,你真的想返回-1为什么不让异常冒泡?)赶超Exception应该是非常罕见的 - 基本上只在盛大运营的顶层(如Web服务请求),以避免在可以继续执行其他操作时终止进程。

+0

我是StreamReader的实际访问指定文件的印象,并且因此,我需要模拟它。从你说过的话,即时通讯假设我错了?捕捉异常的想法是因为我想让程序通过所有的检查。然后它检查errorMessage中是否包含任何内容。如果是这样,它不会让用户继续进行并通知他们错误。我认为这将是最好的一次,而不是1个错误让所有的错误,纠正它,重新运行,下一个错误,正确的是等(这可能是一个有缺陷的方法吗?) – 2012-08-09 09:50:18

+1

@HansRudel:不,它读取*流*。任何流。碰巧有一些便利的构造函数可以为你创建一个'FileStream',但也有其他的可以使用任何流。 – 2012-08-09 10:02:12

+0

这是正确的吗? (请参阅编辑原始问题的底部。)你如何确定你是否需要嘲笑一些东西。即StreamReader等? – 2012-08-09 11:23:29