chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
0 votes
Hi,

I'm evaluating TypeMock for my projects and ran into astrange problem when trieing to mock Database calls

Here my code i want to test:
public DataTable GetData()
        {
            SqlCommand c = SPCommand(SP_GetData);
            int res;
            c.Connection.Open();
            SqlDataAdapter ad = new SqlDataAdapter(c);

            DataTable ret = new DataTable();

            try
            {
                res = ad.Fill(ret);
            }
            finally
            {
                c.Connection.Close();
            }

            return ret;
        }

and here my UnitTest:
[Test]
        [VerifyMocks]
        public void GetData_Test()
        {
            string spName = "SP_GetData";
            using (RecordExpectations rec = RecorderManager.StartRecording())
            {
                rec.DefaultBehavior.CheckArguments();
                rec.VerifyMode = VerifyMode.Normal;

                var conn = new SqlConnection(fakeConnStr);
                var cmd = new SqlCommand
                {
                    Connection = conn,
                    CommandText = spName,
                    CommandType = CommandType.StoredProcedure
                };
                cmd.Connection.Open();

               
                Mock SqlDataAdapterMock = MockManager.MockAll<SqlDataAdapter>();
                SqlDataAdapterMock.ExpectAndReturn("Fill", new DynamicReturnValue(MockFill));
                
              
                DataTable dtDummy = new DataTable();
        
                cmd.Connection.Close();
            }
            var t = new DALClass(fakeConnStr);
            DataTable dt = t.GetSynchronisationErrors();

            Assert.That(dt.Columns["Col1"].DataType == typeof(int));
            Assert.That(dt.Columns["Col2"].DataType == typeof(char));
            Assert.That(dt.Columns["Col3"].DataType == typeof(string));
        }

        public object MockFill(object[] parameters, object context)
        {
            DataTable dt = (DataTable) parameters[0];


            dt.Columns.Add("Col1",typeof(int));
            dt.Columns.Add("Col2",typeof(char));
            dt.Columns.Add("Col3",typeof(string));

            dt.Rows.Add(new object[] { 1, '1', "1" });
            dt.Rows.Add(new object[] { 2, '2', "2" });
            dt.Rows.Add(new object[] { 3, '3', "3" });
           
            return 3;
        }


When running my test i get the following TypeMockException:
TypeMock.TypeMockException:
*** Cannot return a value for IpcClientChannel.get_ChannelName() because no value was set. use recorder.Return().

What i'm doing wrong? as far as i understand the lines:
Mock SqlDataAdapterMock = MockManager.MockAll<SqlDataAdapter>();
SqlDataAdapterMock.ExpectAndReturn("Fill", new DynamicReturnValue(MockFill));

should instruct to mock the SqlDataAdapter and fill the DataTable passed in my code with the MockFill Method.

thanks in advance for your help,
chris
asked by chubinger (680 points)

5 Answers

0 votes
Hi Chris,

First, I think that the problem is that you are using MockAll inside the recording block, which you shouldn't do. You can use it before the recording block.

However, I think your going a bit off track with this test. It looks like you are trying to test that the injected DataTable is correct. Seems a bit useless, unless you are trying out Isolator. Or have I misunderstood the test?

Instead of mocking all the calls in the method, and then filling the table instead of the call to Fill, why not mock the entire GetData method and return a pre-prepared data table?

I need a bit more info on what you are trying to achieve here. I hope I can then help you better.

Thanks,
answered by gilz (14.5k points)
0 votes
Hi,

Now it works - simply moved the MoackAll outside the record block.

Well i know this tests this code:
res = ad.Fill(ret);
...
return ret;

e.g. only the return statment of the method - i mainly tried that as i'd like to get a feling for using Typemock.

Thanks a lot for your quick help.
answered by chubinger (680 points)
0 votes
Hi Chris,

Glad it worked.
If you want to play with Isolator some more, take a look at the new AAA syntax. It's clearer and makes you write less test code. You can read some posts on our blog here.

Thanks
answered by gilz (14.5k points)
0 votes
Hi,

Thanks for the great support.

Now i found another strange behaviour i do not understand.
Basicly When does the order in which i set up my expectation is relevant?

i have a test:

using (RecordExpectations rec = RecorderManager.StartRecording())
            {
rec.DefaultBehavior.CheckArguments();
rec.VerifyMode = VerifyMode.Normal;
// some mor stuff                rec.ExpectAndReturn(db.UpdateSynchronisationError("function", 7737, creationDate), 0);
                rec.ExpectAndReturn(db.CopyCacheToImportExport(creationDate), 0);
}


in this test it does not matter if i swap the last thow expectations - the test is allways green

in this one:
using (RecordExpectations rec = RecorderManager.StartRecording())
            {
                rec.DefaultBehavior.CheckArguments();
                rec.VerifyMode = VerifyMode.Normal;
//...some mor stuff
                rec.ExpectAndReturn(cmd.Parameters["@errorCode"].Value, 0);
                rec.ExpectAndReturn(cmd.Parameters["@creationDate"].Value, DateTime.MaxValue);
}


swappting the last lines here causes the test to fail because of Argument Missmatch

so is there any kind of rule the explains when the order of the expectations is required an when not?

best regards,
chris
answered by chubinger (680 points)
0 votes
Hi Chris,

The order of expectations makes sense only for a single method. That means, for different types, the order of expectations is irrelevant. It is also true for different method on the same type.

When you record an 2 expectations on a method, the order determines what will be returned first. Unless... it comes to overloads and indexers.

Because of an internal limitation (which we are working on right now), overloaded methods are not supported in Isolator. The indexer, is actually get_item() when according to the parameter's type the correct indexer is called. So what you see is the outcome of writing the two expectations on get_item, the first one matches the return type in your code (because you call the int version first), but the second isn't (because string doesn't match).

There is no nice workaround for that. It could work if all your indexers return objects of the same type. I'll update you once it's done.

Thanks
answered by gilz (14.5k points)
...