Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
510 views
in Technique[技术] by (71.8m points)

c# - How to mock an SqlDataReader using Moq - Update

I'm new to moq and setting up mocks so i could do with a little help. How do I mock up an SqlDataReader using Moq?

Update

After further testing this is what I have so far:

private IDataReader MockIDataReader()
{
    var moq = new Mock<IDataReader>();
    moq.Setup( x => x.Read() ).Returns( true );
    moq.Setup( x => x.Read() ).Returns( false );
    moq.SetupGet<object>( x => x["Char"] ).Returns( 'C' );

    return moq.Object;
}

private class TestData
{
    public char ValidChar { get; set; }
}

private TestData GetTestData()
{
   var testData = new TestData();

   using ( var reader = MockIDataReader() )
   {
       while ( reader.Read() )
       {
           testData = new TestData
           {
               ValidChar = reader.GetChar( "Char" ).Value
           };
       }
   }

   return testData;
}

The issue you is when I do reader.Read in my GetTestData() method its always empty. I need to know how to do something like

reader.Stub( x => x.Read() ).Repeat.Once().Return( true ) 

as per the rhino mock example: Mocking a DataReader and getting a Rhino.Mocks.Exceptions.ExpectationViolationException: IDisposable.Dispose(); Expected #0, Actual #1

question from:https://stackoverflow.com/questions/2643909/how-to-mock-an-sqldatareader-using-moq-update

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Moq has an ability to run some code after the method is executed. It is called "Callback". Modify your code this way and it will work:

private IDataReader MockIDataReader()
{
    var moq = new Mock<IDataReader>();

    bool readToggle = true;

    moq.Setup(x => x.Read())
         // Returns value of local variable 'readToggle' (note that 
         // you must use lambda and not just .Returns(readToggle) 
         // because it will not be lazy initialized then)
        .Returns(() => readToggle) 
        // After 'Read()' is executed - we change 'readToggle' value 
        // so it will return false on next calls of 'Read()'
        .Callback(() => readToggle = false); 

    moq.Setup(x => x["Char"])
        .Returns('C');

    return moq.Object;
}

private class TestData
{
    public char ValidChar { get; set; }
}

private TestData GetTestData()
{
    var testData = new TestData();

    using ( var reader = MockIDataReader() )
    {
       testData = new TestData
       {
           ValidChar = (Char)reader["Char"]
       };
   }

   return testData;
}

But what if it will be required IDataReader to contain not only single row, but several? Well, here is a sample:

// You should pass here a list of test items, their data
// will be returned by IDataReader
private IDataReader MockIDataReader(List<TestData> ojectsToEmulate)
{
    var moq = new Mock<IDataReader>();

    // This var stores current position in 'ojectsToEmulate' list
    int count = -1;

    moq.Setup(x => x.Read())
        // Return 'True' while list still has an item
        .Returns(() => count < ojectsToEmulate.Count - 1)
        // Go to next position
        .Callback(() => count++);

    moq.Setup(x => x["Char"])
        // Again, use lazy initialization via lambda expression
        .Returns(() => ojectsToEmulate[count].ValidChar);

    return moq.Object;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...