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
Welcome to Typemock Community! Here you can ask and receive answers from other community members. If you liked or disliked an answer or thread: react with an up- or downvote.
0 votes
foreach (DataRow row in dataTable.Rows)
foreach (DataColumn column in dataTable.Columns)
HttpContext.Current.Response.Write(row[column.ColumnName].ToString());

I have the above code (My table has 3 rows and 3 columns) and I tried to mock and verify the HttpContext.Current.

My approach:
I wrote the following code to mock the class:
Isolate.Fake.StaticMethods(typeof(HttpContext), Members.ReturnRecursiveFakes);

And the following to verify:
foreach (DataRow row in dataTable.Rows)
{
foreach (DataColumn column in dataTable.Columns)
{
string toWrite = row[column.ColumnName].ToString();
Action action = delegate() { HttpContext.Current.Response.Write(toWrite); };
Isolate.WhenCalled(action).IgnoreCall();

}
}

Problem:

It's too slow when the verification code is run. Each execution loop takes about 5 seconds, so for my test table it takes about 45 (3*3*5) seconds to execute!

Any solution?
asked by Ben (3k points)

5 Answers

0 votes
What are you trying to accomplish in your test? I'm not exactly following.
answered by boo (21.8k points)
0 votes
Although I'm not really getting what you're trying to mock exactly, but the extension methods I wrote will help - http://www.aaron-powell.com/blog/march- ... roids.aspx

They are designed to specify the number of times a certain mock will be "live" for, allowing you to specify when you want the loop to break out.

If you know exactly where in the HttpContext you want to mock you should just mock HttpContext (Isolate.Fake.Instance<HttpContext>()).

I've done HttpContext mocking, it's ok, but not super reliable. Here's a simple example:
var fakeContext = Isolate.Fake.Instance<HttpContext>();
Isolate.WhenCalled(() => HttpContext.Current).WillReturn(fakeContext);


Then just keep adding to it
answered by slace (2.4k points)
0 votes
For more clarification, the production code is:

public void MyMethod()
{

foreach (DataRow row in dataTable.Rows)
foreach (DataColumn column in dataTable.Columns)
HttpContext.Current.Response.Write(row[column.ColumnName].ToString());

}

How do you write a unit test for this method? we need to mock the bolded line, right? I asked how I can do that.

Please let me know if it's not clear yet.
answered by Ben (3k points)
0 votes
Ben,

For the purpose of the test I think you should isolate the dependency in the data layer, and use a fake data collection. I don't know how you receive this data table in the code under test, but a complete test may look something like this:
// fake out any following call to Write() 
Isolate.WhenCalled(() => HttpContext.Current.Response.Write("")).IgnoreCall();

// prepare fake data structure to iterate over
var fakeTable = Isolate.Fake.Instance<DataTable>();
var fakeRow = Isolate.Fake.Instance<DataRow>();
var fakeColumn = Isolate.Fake.Instance<DataColumn>();
Isolate.WhenCalled(() => fakeColumn.ColumnName).WillReturn("TestColumn");
Isolate.WhenCalled(() => fakeRow["TestColumn")).WillReturn("TestOutput");

// make the Rows and Columns collections return our fake data
Isolate.WhenCalled(() => fakeTable.Rows).WillReturnCollectionValuesOf(new [] { fakeRow });
Isolate.WhenCalled(() => fakeTable. Columns).WillReturnCollectionValuesOf(new [] { fakeColumn });

// call the method under test with the fake data table
var target = new ClassUnderTest();
target.DoStuff(fakeTable);

// now verify the fake data has been accessed properly
Isolate.Verify.WasCalledWithExactArguments(() => HttpContext.Current.Response.Write("TestOutput"));


Let me know if this helps.

Thanks,
Doron
Typemock Support
answered by doron (17.2k points)
0 votes
Thanks Doron.

The dataTable is fine as I can pass to the MyMethod as input parameter.

Your comments inspired me to find the solution to my problem:

// mock HttpResponse
HttpResponse fakeHttpResponse = Isolate.Fake.Instance<HttpResponse>();
Isolate.WhenCalled <HttpResponse>(delegate() { return HttpContext.Current.Response; }).WillReturn(fakeHttpResponse);

// mock Response.Write()
Isolate.WhenCalled(delegate() { fakeHttpResponse.Write(""); }).IgnoreCall();

Then for verification:

foreach (DataRow row in dataTableForTest.Rows)
{
foreach (DataColumn column in dataTableForTest.Columns)
{
string toWrite = row[column.ColumnName].ToString() + ",";
Isolate.Verify.WasCalledWithExactArguments(
delegate() { fakeHttpResponse.Write(toWrite); });
}

}

The performance issue is resolved as well as it doesn't use the HttpContext.Current.Response.Write().

Lessons I learned:
1) At the time of mocking, we don't need to write the mocking statement several times if that dependency is used in the code several times e.g. my loop scenario

2) At the time of mocking, the input arguments don't matter. At the time of verification, we can verify the input arguments. Having said that this is in contrast with how NMock works as you can specify the expected method arguments when mocking using NMock. NMock syntax seems neater to me to be honest in this case. Maybe a feature for improvement for TypeMock?
answered by Ben (3k points)
...