2016-02-04 67 views
4

我是Moq的新手,我正在努力編寫單元測試來測試將SqlDataAdapter轉換爲System.DataView的方法。這是我的方法:如何模擬IDataReader測試方法,將SqlDataReader轉換爲System.DataView

private DataView ResolveDataReader(IDataReader dataReader) 
{ 
    DataTable table = new DataTable(); 

    for (int count = 0; count < dataReader.FieldCount; count++) 
    { 
     DataColumn col = new DataColumn(dataReader.GetName(count), 
             dataReader.GetFieldType(count)); 
     table.Columns.Add(col); 
    } 

    while (dataReader.Read()) 
    { 
     DataRow dr = table.NewRow(); 
     for (int i = 0; i < dataReader.FieldCount; i++) 
     { 
      dr[i] = dataReader.GetValue(dataReader.GetOrdinal(dataReader.GetName(i))); 
     } 
     table.Rows.Add(dr); 
    } 

    return table.DefaultView; 
} 

我試圖創建創建類似:

var dataReaderMock = new Mock<IDataReader>(); 
var records = new Mock<IDataRecord>(); 
dataReaderMock.Setup(x => x.FieldCount).Returns(2); 
dataReaderMock.Setup(x => x.Read()).Returns(() => records); 

我想通過一些數據並驗證它轉換。

謝謝。

+1

你有什麼問題? –

+0

我無法用僞數據填充模擬對象。這不允許我測試我的方法中的邏輯。 – Hristo

+0

如何實現'ResolveDataReader'方法?我需要看代碼才能舉一個例子... –

回答

6

你與你的模擬是正確的軌道,但dataReaderMock.Setup(x => x.Read()).Returns(() => records);是你出錯的地方.Read返回一個布爾,而不是記錄本身,它們是用你的方法讀出IDataReader


要安排嘲笑

var dataReader = new Mock<IDataReader>(); 
dataReader.Setup(m => m.FieldCount).Returns(2); // the number of columns in the faked data 

dataReader.Setup(m => m.GetName(0)).Returns("First"); // the first column name 
dataReader.Setup(m => m.GetName(1)).Returns("Second"); // the second column name 

dataReader.Setup(m => m.GetFieldType(0)).Returns(typeof(string)); // the data type of the first column 
dataReader.Setup(m => m.GetFieldType(1)).Returns(typeof(string)); // the data type of the second column 

您可以安排列品嚐到模擬更真實數據,類型等。在您的系統,只需確保第一計數, GetName的數量和GetFieldType的數量是同步的。

要安排.Read(),我們可以使用SetupSequence:

dataReader.SetupSequence(m => m.Read()) 
    .Returns(true) // Read the first row 
    .Returns(true) // Read the second row 
    .Returns(false); // Done reading 

要在測試中使用此可以提取成一個方法:

private const string Column1 = "First"; 
private const string Column2 = "Second"; 
private const string ExpectedValue1 = "Value1"; 
private const string ExpectedValue2 = "Value1"; 

private static Mock<IDataReader> CreateDataReader() 
{ 
    var dataReader = new Mock<IDataReader>(); 

    dataReader.Setup(m => m.FieldCount).Returns(2); 
    dataReader.Setup(m => m.GetName(0)).Returns(Column1); 
    dataReader.Setup(m => m.GetName(1)).Returns(Column2); 

    dataReader.Setup(m => m.GetFieldType(0)).Returns(typeof(string)); 
    dataReader.Setup(m => m.GetFieldType(1)).Returns(typeof(string)); 

    dataReader.Setup(m => m.GetOrdinal("First")).Returns(0); 
    dataReader.Setup(m => m.GetValue(0)).Returns(ExpectedValue1); 
    dataReader.Setup(m => m.GetValue(1)).Returns(ExpectedValue2); 

    dataReader.SetupSequence(m => m.Read()) 
     .Returns(true) 
     .Returns(true) 
     .Returns(false); 
    return dataReader; 
} 

(或者,你可以安排這在Setup上,如果這對您的測試類更有意義 - 那麼dataReader模擬將是一個字段,而不是返回的值)

示例測試。然後,它可以使用,如:

[Test] 
public void ResovleDataReader_RowCount() 
{ 
    var dataReader = CreateDateReader(); 
    var view = ResolveDataReader(dataReader.Object); 
    Assert.AreEqual(2, view.Count); 
} 

[Test] 
public void ResolveDataReader_NamesColumn1() 
{ 
    var dataReader = CreateDataReader(); 
    var view = ResolveDataReader(dataReader.Object); 
    Assert.AreEqual(Column1, view.Table.Columns[0].ColumnName); 
} 

[Test] 
public void ResolveDataReader_PopulatesColumn1() 
{ 
    var dataReader = CreateDataReader(); 
    var view = ResolveDataReader(dataReader.Object); 
    Assert.AreEqual(ExpectedValue1, view.Table.Rows[0][0]); 
} 

// Etc.. 

(我用NUnit的,但它會與測試方法只是不同的屬性和不同的斷言語法類似,不同的測試框架)


順便說一句,我得到了上述改變ResolveDataReaderinternal和設置InternalsVisibleTo工作,但我假設你有一個網關到這個私有方法,因爲你已經爲你想測試沒有得到儘可能它。