Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 494
lancscoder Avatar asked Apr 15 '10 08:04

lancscoder


People also ask

What can be mocked with MOQ?

Unit testing is a powerful way to ensure that your code works as intended. It's a great way to combat the common “works on my machine” problem. Using Moq, you can mock out dependencies and make sure that you are testing the code in isolation.

How does MOQ mock work?

Mock objects allow you to mimic the behavior of classes and interfaces, letting the code in the test interact with them as if they were real. This isolates the code you're testing, ensuring that it works on its own and that no other code will make the tests fail.


2 Answers

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; } 
like image 149
Monsignor Avatar answered Sep 19 '22 08:09

Monsignor


I was just trying to figure this out myself. Not sure if this is new functionality in Moq, but it appears there is a simpler way than @Monsignor's answer.

Use Moq's SetupSequence method. Your code simply becomes:

private IDataReader MockIDataReader() {     var moq = new Mock<IDataReader>();     moq.SetupSequence( x => x.Read() )        .Returns( true )        .Returns( false );     moq.SetupGet<object>( x => x["Char"] ).Returns( 'C' );      return moq.Object;  } 
like image 39
mikesigs Avatar answered Sep 20 '22 08:09

mikesigs