I have writen a class which implements IEnumerable<T>. I have used
"yield return" to implement this, as follows:
public IEnumerator<int> GetEnumerator()
{
foreach (int i in items)
{
yield return item;
}
}
Now, I have written unit tests to cover this, but can't seem to get
coverage of an auto-generated MoveNext() method of the Enumerator. The
coverage window shows the following:
MyClass`2.<GetEnumerator>d__0 3 21.43 % 11 78.57 %
MoveNext() 3 21.43 % 11
78.57 %
[Note I've changed names to protect the identity of innocent
classes! ;)]
...as you can see, three blocks of code are not being covered.
However, when I double click the uncovered code, all code is displayed
in green, suggesting that it has been covered. While I appreciate that
100% coverage is not possible and certainly shouldn't be the aim (80%
is a more realistic aim), it's really annoying me that I can't cover
this.
I've tried to instantiate an enumerator directory and call the MoveNext()
method, but I'm still getting three uncovered lines. I also tried marking the
GetEnumerator as [System.Diagnostics.DebuggerHidden] and that made no
difference.
Does anyone know how to solve this?
Thanks in advance,
Steve.
Thanks for your post.
This is a known issue. It is reported at
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?Feedba
ckID=329830.
It will be fixed in the upcoming beta of Visual Studio 2010.
In order to workaround the issue, you have two options:
1. Writing test code to cover the error logic code in MoveNext
As Marc Popkin-Paine said in the connect website, one way to workaround the
issue is rewrite the foreach as a while and move through the iterator
manually. This way can run the code blocks correspond to the error state
when you try to move the iterator beyond the final state. In order to
verify it, I wrote the following test code and it works well:
-----------------------------------
[TestMethod()]
public void GetEnumeratorTest()
{
Enumerator e = new Enumerator();
IEnumerator<int> er = e.GetEnumerator();
while (er.MoveNext())
{
Console.WriteLine(er.Current);
}
// The following line force the error state code executing
er.MoveNext();
}
-----------------------------------
2. Exclude compiler generated code from code coverage report
The only way, currently, to filter functions from coverage is to not
instrument them in the first place. Check out vsinstr's /exclude
command-line option. You can /exclude functions that you don't want to
show up in your coverage numbers. Here is the link:
http://msdn.microsoft.com/en-us/library/ms182402.aspx
Use the following name pattern to exclude:
namespace.MyClass`2.<GetEnumerator>d__0.*
This method has a limitation that you must generate code coverage report
through command line.
Please let me know if both methods work for you. Or you can wait for the
next beta of VS 2010 for the fix. Thanks.
Have a nice day.
Regards,
Hongye Sun (hon...@online.microsoft.com, remove 'online.')
Microsoft Online Community Support
Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
msd...@microsoft.com.
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.
Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within?2 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions. Issues of this
nature are best handled working with a dedicated Microsoft Support Engineer
by contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
Thanks for your reply! I'm glad that other people have experienced the same
problem. I did have a look on Google, but couldn't find any solutions.
Your second solution is not really viable, as we run everything from the
IDE. I’d rather not have to wait until 2010 either! ;)
So, the first option it is! I decided to write a test solution to prove the
concept. Here is the class I’m testing:
public class Items : IEnumerable<int>
{
private int[] items = new int[] { 1, 2, 3, 4 };
#region IEnumerable<int> Members
public IEnumerator<int> GetEnumerator()
{
foreach (int item in items)
{
yield return item;
}
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator
System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
…and here is the unit test:
[TestMethod()]
public void ItemsConstructorTest()
{
Items t1 = new Items();
foreach (int i in t1)
{
System.Console.WriteLine(i);
}
IEnumerator<int> e1 = t1.GetEnumerator();
while (e1.MoveNext())
{
System.Console.WriteLine(e1.Current);
}
e1.MoveNext();
// =======================
IEnumerable t2 = new Items();
IEnumerator e2 = t2.GetEnumerator();
while (e2.MoveNext())
{
System.Console.WriteLine(e2.Current);
}
e2.MoveNext();
}
…as you can see, I’ve opted to write just one test to try and get 100%
coverage. In the “real world”, this would be a number of separate tests.
I believe I have now followed the advice in option 1. However, this still
isn’t giving me 100% test coverage. I’m getting the following entry in the
coverage:
Items.<GetEnumerator>d__0 2 13.33 % 13
86.67 %
MoveNext() 2 13.33 % 13 86.67 %
The first line is the summary, and the second the detail. Option 1 has given
slightly better coverage, but there still seems to be two elusive lines of
code! Could you suggest how to edit my tests to resolve this?
Many thanks,
Steve.
Thanks for your reply.
I found what the problem is. For different yield code, .NET compiler
generated different IL code. What I tested is the code below:
public IEnumerator<int> GetEnumerator()
{
int i = 0;
while (i < items.Count)
{
yield return items[i++];
}
}
foreach generated different code from while. After testing, I could not
find a way to cover foreach, but while is proved to be covered by the
testing code in my previous reply. Is it possible for yout rewrite your
GetEnumerator method to use while instead of foreach? The result are the
same.
Please let me know if it works. I will be waiting for your reply. Thanks.
Regards,
Hongye Sun (hon...@online.microsoft.com, remove 'online.')
Microsoft Online Community Support
Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
msd...@microsoft.com.
?
Yep, it worked! Thanks very much for that!
I implemented it with a for...loop in the end. Is there are reason why you'd
choose a while loop over a for...loop?
Cheers,
Steve.
for and while generate same code. I choose while because in connect
website, product group mentioned it.
I am very glad that the issue has been resolved. Thanks for using our
Microsoft Newsgroup Service.
Have a nice day.
Regards,
Hongye Sun (hon...@online.microsoft.com, remove 'online.')
Microsoft Online Community Support
Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
msd...@microsoft.com.
This posting is provided "AS IS" with no warranties, and confers no rights.