Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loop inside a unit test

Tags:

Can we have a loop inside a unit test?

My method returns an IEnumerable<IEnumerable>, I would like to unit test this logic where the IEnumerable<IEnumerable> is created. Basically I wanna test if the count of elements in the IEnumerable are as expected.

I cannot figure out an alternate way to test the inner IEnumerable without having a looping statement. Please let me know if this is a good practice.

like image 290
Shankar Raju Avatar asked May 01 '11 09:05

Shankar Raju


People also ask

Can we use for loop in unit testing?

Yes you can have loops in unit test, but with caution. As mentioned by Alex York, loops are acceptable if you test one thing; i.e. one expectation.

What are the three parts of a unit test?

A typical unit test contains 3 phases: First, it initializes a small piece of an application it wants to test (also known as the system under test, or SUT), then it applies some stimulus to the system under test (usually by calling a method on it), and finally, it observes the resulting behavior.


2 Answers

There is no technical reason you can't do it. You can have multiple Assert statements in a unit test. Having an Assert statement in a loop is simply a shorthand way of having multiple Assert statements in a test.

However, some people think there should only be a single Assert statement in a unit test.

I personally don't agree - I think a test should test a single thing - and in order to do that sometimes you may need more than one Assert statement.

If your method returns an IEnumerable of Product's, and each Product contains an IEnumerable of Color's, then I think the following test is is fine:

[Test] public void All_products_should_have_some_colors() {     var products = GetProducts();      foreach (var product in products)     {         Assert.IsNotEmpty(product.Colors);     } } 

However, you do need to be aware that if the IEnumerable contains 0 elements, the loop will never execute any of the Assert statements and your unit test will "pass" - whereas you probably would have intended it to fail.

To remedy that situation, you could have a separate test making sure that there are more than 0 elements in the IEnumerable (i.e. that GetProducts does actually return some Product's):

Assert.IsNotEmpty(products); 
like image 73
Alex York Avatar answered Sep 21 '22 12:09

Alex York


One reason to avoid writing a loop in a test would be to keep the test concise and readable at a glance. Since you have tagged the question with NUnit and you say you just want to test that the element count is as expected, consider making your Asserts using the NUnit Constraints.

For example,

IEnumerable<IEnumerable<char>> someStrings = new[] { "abc", "cat", "bit", "hat" };  Assert.That(someStrings, Has.All.With.Length.EqualTo(3).And.All.Contains("a")); 

fails with the message:

Expected: all items property Length equal to 3 and all items String containing "a" But was: < "abc", "cat", "bit", "hat" >

but passes if you change "bit" to "bat".

The book xUnit Test Patterns: Refactoring Test Code By Gerard Meszaros

has many great answers to questions such as yours.

like image 41
Grokodile Avatar answered Sep 21 '22 12:09

Grokodile