Unit testing in C# how to? - c#

I am new in the world of unit testing in C#.
I have a piece of code in my Main.cs
public static string Generate(int length)
{
char[] chars = "$%##!*abcdefghijklmnopqrstuvwxyz1234567890?;:ABCDEFGHIJKLMNOPQRSTUVWXYZ^&".ToCharArray();
string password = string.Empty;
Random random = new Random();
for (int i = 0; i < length; i++)
{
int x = random.Next(1, chars.Length);
if (!password.Contains(chars.GetValue(x).ToString()))
password += chars.GetValue(x);
else
i--;
}
return password;
}
now i don't know how to test this code with unit tests can someone give me a example?
EDIT:
I have make a test code
[TestMethod]
[Timeout(1000)]
public void RenderingPasswordShouldHaveMaximumSize()
{
var amountOfCharacters = Int32.MaxValue;
var generator = new PasswordGenerator();
var target = generator.Generate(amountOfCharacters);
// TODO
Assert.Fail("This method should throw an exception if you try to create a password with too many characters");
}
But it gives me the following error: Message: Test 'RenderingPasswordShouldHaveMaximumSize' exceeded execution timeout period can someone help me with this needs to have a max size of 74!

the idea of unit testing is to put something in a small method of you and check if the result is ok.
Visual Studio there is a project template for that. and there are also other tools like NUnit oderXUnit for tests in C#
There is a great pluralsight course:
and a webcast of Uncle Bob in which he demonstrates test driven development http://cleancoders.com/codecast/clean-code-episode-6-part-1/show
See also "Verifying Code by using Unit Tests" at msdn

A simple example using NUnit. Here I'm testing that when I pass 0 as an argument, nothing is generated (perhaps you should throw an Exception?)
[TextFixture]
public class Tests {
[Test]
public void Test_Length0_ReturnsNothing() {
string result = Generate(0);
Assert.IsTrue(string.IsNullOrEmpty(result));
}
}
You can write then similar tests (eg. to make sure it include the characters you want, etc).

There are much nuances in unit testing. I would recommend you to read book about unit testing "The Art of Unit Testing: With Examples in .Net".
There are described a lot of techniques and approach in unit testing. You can also find many examples here.

var amountOfCharacters = Int32.MaxValue;
var generator = new PasswordGenerator();
var target = generator.Generate(amountOfCharacters);
You're specifying the number of characters the password should contain as 2,147,483,647 characters...
chars.Length
There's only 74 possible values in your array.
No doubt it times out because the loop takes longer to iterate 2.2 billion times trying to find the last few values in your array.
for (int i = 0; i < length; i++)
Your logic changes too since you're not specifying the length of the password, but the number of iterations you want to do.

Related

xUnit tests failing to Assert.Equal two equal values

I'm trying to do an xUnit test on a function and it is failing. Went with the debuger and all the values are as expected. the expected result is equal with the actual result. So for the next step, trying to figure out why it is failing, I assigned the same values for the input and the expected result (without using the function I wanted to test) to make sure both are equal then used the function Asser.Equal(expectedResult, input) but again I ended up with an error (the actual and expected results are not the same) even though I made them exactly the same. The tests I'm trying to make is on structures. The next step , after instead of assigning the values for the expectedResult, I just made expectedResult = input and used Assert.Equal(expectedResult, input) and now the tests were successful. My question would be, why doesn't it work when I assign the values separately to the expectedResult and why it does work when I make the expectedResult = with the input. Is this because of the structures from the code?
[Fact]
// this example doesn't work
public void GenerateGeneralRanking_OneSerriesAsInput_ShouldReturnSortedRanking()
{
Contest input = new Contest();
input.GeneralRanking.Contestants = new Contestant[3];
Contestant input1 = new Contestant ( "Ion", "Romania", 9.500 );
Contestant input2 = new Contestant("Alex", "Romania", 9.300);
Contestant input3 = new Contestant("Dan", "Romania", 9.200);
input.GeneralRanking.Contestants[0] = input1;
input.GeneralRanking.Contestants[1] = input2;
input.GeneralRanking.Contestants[2] = input3;
Contest expectedRanking = new Contest();
expectedRanking.GeneralRanking.Contestants = new Contestant[3];
expectedRanking.GeneralRanking.Contestants[0] = input1;
expectedRanking.GeneralRanking.Contestants[1] = input2;
expectedRanking.GeneralRanking.Contestants[2] = input3;
Assert.Equal(input, expectedRanking);
}
And If I make it like this it works ->
[Fact]
public void GenerateGeneralRanking_OneSerriesAsInput_ShouldReturnSortedRanking()
{
Contest input = new Contest();
input.GeneralRanking.Contestants = new Contestant[3];
Contestant input1 = new Contestant ( "Ion", "Romania", 9.500 );
Contestant input2 = new Contestant("Alex", "Romania", 9.300);
Contestant input3 = new Contestant("Dan", "Romania", 9.200);
input.GeneralRanking.Contestants[0] = input1;
input.GeneralRanking.Contestants[1] = input2;
input.GeneralRanking.Contestants[2] = input3;
Contest expectedRanking = new Contest();
expectedRanking.GeneralRanking.Contestants = new Contestant[3];
// This would be the changed part
expectedRanking = input;
Assert.Equal(input, expectedRanking);
}
The function I'm trying to test makes the same thing as the first example of the code, so I typed the values for the sake of the example. Sorry if I missed some info and thank you in advance
I would guess that Contest does not implement IEquatable<Contest> or otherwise override Equals(object). Therefore Assert.Equal will only work when the objects are reference equal. If you don't want to do this, you can create your own IEqualityComparer<Contest> and use the overload Assert.Equal(expectedRanking, input, equalityComparer). Best of luck
I'd suggest to use the Fluent Assertions library for this kind of assert checks in unit tests. Instead of rigid equality, you are looking for equivalency.
Then your assert becomes:
input.Should().BeEquivalentTo(expectedRanking);
and this doesn't look for references, only values!

Nunit: TestCaseSource does not expect to generate all test cases?

Hi everyone I have a problem with generate test cases for TestCaseSource. I wrote this code for tests:
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
namespace HeapSort.Tests
{
[TestFixture]
public class Tests
{
[Test, TestCaseSource(typeof(TestsGenerator),"TestCases")]
public void IsEqualCollections(int[] received, int[] expected)
{
CollectionAssert.AreEqual(received, expected);
}
}
public class TestsGenerator
{
public static IEnumerable<TestCaseData> TestCases
{
get
{
for (var i = 0; i < 25; i++)
{
int[] t1 = GenerateCollection(i), t2 = t1.ToArray();
HeapSort.Sort(t1);
Array.Sort(t2);
yield return new TestCaseData(t1, t2);
}
}
}
private static int[] GenerateCollection(int seed)
{
var rnd = new Random(seed+DateTime.Now.Millisecond);
int size = rnd.Next(100, 10000);
int[] array = new int[size];
for (var i = 0; i < size; i++)
array[i] = rnd.Next(-100, 100);
return array;
// return Enumerable
// .Repeat(100, rnd.Next(100, 10000))
// .Select(i => rnd.Next(-100, 100))
// .ToArray();
}
}
}
Where is the problem? Rather than get 25 tests, I get from 1 to 8. And often at the starting point of testing it shows that the tests are 7/8 and in the end there is only one test case.
How can I solve this problem?
UPD1: What's interesting is when I run tests through the console I handle all 25 tests how do I achieve the same results through the GUI!?
P.S. sorry for my bad english.
Perhaps I should mention that I'm working under Ubuntu in Rider
DateTime.Now is normally not very accurate. Your loop is generating many identical tests because they are all starting from the same seed. Why are you using a seed rather than simply letting Random work on its own?
Different runners will handle identical test in different ways. If you indicate what runner you are using to execute your tests, I can edit this answer with more information. However, in general, you most certainly don't want to generate a bunch of tests with the same data. They don't do anything for you!
The reason is TestExplorer looks at the name of test case and groups ones with equal names. So you don't see all test cases results. As reason is TestExplorer you don't have the same problem running test using console. Look at this issue for details. According to the issue there are two solutions:
create class for your test case and override ToString() method
making it return unique values for each test case.
use TestCaseData class and its method SetName to set unique name for each test.

How do I get the best performance from a Windows/wcf Service in C#?

I'm currently working on a Windows Service that will be handling the acquisition of data from multiple measurement instruments connected via USB to my computer. It will be sending some data to an SQL database but I am also creating another application for the machine to be able to view the data locally in real-time and I'll be dealing with arrays/lists with over 7,000,000 elements in the worst case scenarios.
Currently I'm using WCF with NetNamedPipeBinding for inter-process communication and it works great (I can transfer an array with over 7 million doubles in less than a quarter second). So I don't need answers urgently, but I am curious if there are faster ways of accessing the data in the service quicker or more easily.
I have been thinking of delving into unmanaged memory and having the service return a pointer to the array, or something similar. However I don't want to bother with that if the gains are minimal. It's just that when passing a class (I bet a struct will have less overhead) the performance tanks and I am trying to get a good foundation in case I start dealing with more complex data types.
Service related code
public class testclass
{
public double dub1 {get;set;}
public double dub2 {get;set;}
}
public testclass[] GetList(int n)
{
sw.Restart();
testclass[] numbers = new testclass[n];
for (var i = 0; i < n; i++)
{
numbers[i] = new testclass { dub1 = i, dub2 = i };
}
numbers[0].dub1 = (double)sw.ElapsedMilliseconds;
return numbers;
}
public double[] GetDoubles(int n)
{
sw.Restart();
double[] numbers = new double[n];
numbers[0] = (double)sw.ElapsedMilliseconds;
return numbers;
}
Client Related Code
class Program
{
static void Main(string[] args)
{
while (1 == 1)
{
Console.WriteLine("Size of List");
var number1 = int.Parse(Console.ReadLine());
var sw = new Stopwatch();
var test = new ServiceReference1.CalculatorClient();
sw.Restart();
var list = test.GetDoubles(number1).ToList();
Console.WriteLine("Response Time: "+ sw.ElapsedMilliseconds);
Console.WriteLine("Time to make list: "+list[0]);
}
}
}
GetDoubles Performance
GetList Performance
Im just guessing here but I expect that serialization may be part of the issue, there are two steps to dealing with this (at least). One is to use DTO's to make sure you are only passing what is needed and are using performant data types, the other would be to look at using a different serializer, I have heard of protobuf-net but have never used it.
I know your above example is trivial but if your test class could create a byte array DTO and accept one as a constructor on the client side you might have a pattern that helps.

Loop inside a unit test

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.
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);
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.
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.
If you use loops, then I recommend that you must do two things:
As mentioned above, test for a non-empty iteration set. Iterating over an empty set is a false positive. False positive results are bane of all automated testing because nobody double checks a green result.
Include a test description that describes the current iteration. At a minimum include the iteration index.
Here is an example from my testing of the Greater Than property of an object.
[Test]
public void TestCompare_XtoY_GreaterThan()
{
int numObjects = mOrderedList.Count;
for (int i = 1; i < numObjects; ++i)
{
for (int j = 0; j < i; ++j)
{
string testDescription = string.Format("{0} is greater than {1} which implies\n {2}\n is greater than\n {3}"
, i, j
, mOrderedList[i], mOrderedList[j]
);
Assert.IsTrue(0 < mOrderedList[i].CompareTo(mOrderedList[j]), testDescription);
Assert.IsTrue(0 < mOrderedList[i].Compare(mOrderedList[i], mOrderedList[j]), testDescription);
Assert.IsTrue(0 < mOrderedList[j].Compare(mOrderedList[i], mOrderedList[j]), testDescription);
Assert.Greater(mOrderedList[i], mOrderedList[j], testDescription);
}
}
}
I test that my ordered list is non-empty in the test setup using:
[SetUp]
public void GeneralTestSetup()
{
// verify the iterated sources are not empty
string testDescription = string.Format("The ordered list of objects must have at least 3 elements, but instead has only {0}.", mOrderedList.Count);
Assert.IsTrue(2 < mOrderedList.Count, testDescription);
}
I have multiple Asserts even within my loop, but all of the asserts are testing the single expectation:
if i > j then mOrderedList[i] > mOrderedList[j]
The test description at the iteration level is so you get Failures such as:
10 is greater than 9 which implies
TestActionMethodInfo: [Actions.File, Version=1.0.446.0, File, VerifyReadOnly]
is greater than
TestActionMethodInfo: [Actions.File, Version=1.0.446.0, File, Write]
Expected: True
But was: False
instead of just:
Expected: True
But was: False
The question/debate about my code above:
Is am I testing one thing?
I am asserting on 4 different comparison methods within the object which could be argued as testing 4 things not one. The counter is greater than is greater than is greater than and that all of the methods which make that evaluation should be consistent.

NUnit: Running multiple assertions in a single test

I have been asked to write a testing application that needs to test a new stored procedure on multiple rows in a database, in essence I want to do something like this:
[Test]
public void TestSelect()
{
foreach(id in ids)
{
DataTable old = Database.call("old_stored_proc",id);
DataTable new_ = Database.call("new_stored_proc",id);
Assert.AreEqual(old.Rows[0]["column"],ne_.Rows[0]["column"]);
}
}
When I run this test, if 1 row doesn't match the other, the entire test fails; instead I would like to count how many times the assertion was passed and how many times it has failed. Is there a way to do this with NUnit?
I realize that NUnit might be overkill and this is a simple task without it...I just wanted to learn it. ;)
Seems like you are just Asserting the wrong thing. If you want to check all the values and then assert that there are no errors (or show the number of errors) then try this:
[Test]
public void TestSelect()
{
int errors = 0;
foreach(id in ids)
{
DataTable old = Database.call("old_stored_proc",id);
DataTable new_ = Database.call("new_stored_proc",id);
if (old.Rows[0]["column"] != new_.Rows[0]["column"])
{
errors++;
}
}
Assert.AreEqual(0, errors, "There were " + errors + " errors.");
}
1) If the id's are constant and not looked up at test run time, create a separate unit test fixture for each id. That way you will know which id's are actually failing. See here for a write up on the problems with data driven tests:
http://googletesting.blogspot.com/2008/09/tott-data-driven-traps.html
2) If you need to dynamically look up the id's making it impossible to create a fixture for each id, use akmad's suggestion with one change. Keep a list of id's where the values are not equal and add the list to the error message. It will be extremely difficult to diagnose a failing test that only states the number of errors, as you won't know what id's cause the errors.
3) I don't know how difficult it would be to do in NUnit, but in PyUnit, when we need to run tests on dynamically generated data, we dynamically create tests fixtures and attach them to the TestCase class so that we have a failed test for each piece of data that does not pass. Though I imagine this would be much more difficult without python's dynamic abilities.
I know that the question is specifically about NUnit, but interestingly enough, Gallio/MbUnit has a feature which allows to run and catch several assertions at once.
[Test]
public void MultipleTest()
{
Assert.Multiple(() =>
{
Assert.IsTrue(blabla);
Assert.AreEqual(pik, pok);
// etc.
}
}
The Assert.Multiple is catching all the failing assertions and is going to report them at the end of the test.
I would count the number of rows which do not match and then would write an assertion which will compare this number with 0 and would return the number of non matching strings in the message.
you could also use Assert.Greater for this.
P.S. In principal you should try to do one assertion per unit test. That's the gist of it.
Well you could declare a counter and then assert the value of the counter to determine pass/fail
Also, you could do the bulk of the work in the test setup, and then just create multiple tests.
I'm not clear as to why you need all the assert stmts in the same test.
Based on the objective you laid out, the entire test should fail if one row doesn't match another. Counting the number of times an assertion passes or fails gives you less information than a comparison of the outcome you expected with the outcome you actually got.
I recently had the same issue. I combined the idea of counting errors with Yann Trevin's mention of Assert.Multiple into an extension method for IEnumberable that lets me do things like:
[Test]
public void TestEvenNumbers()
{
int[] numbers = new int[] { 2, 4, 12, 22, 13, 42 };
numbers.AssertAll((num) => Assert.That((num % 2) == 0, "{0} is an odd number", num));
}
Which results in the NUnit output:
TestEvenNumbers:
5 of 6 tests passed; 0 inconclusive
FAILED: 13: 13 is an odd number
Expected: True
But was: False
Expected: 6
But was: 5
And the solution to the OP's problem would be:
[Test]
public void TestSelect()
{
ids.AssertAll(CheckStoredProcedures);
}
private void CheckStoredProcedures(Id id)
{
DataTable old = Database.call("old_stored_proc",id);
DataTable new_ = Database.call("new_stored_proc",id);
Assert.AreEqual(old.Rows[0]["column"], new_.Rows[0]["column"]);
}
Here is the extension method (note that I used "All" instead of "Multiple" for consistency with Linq terminology):
using System;
using System.Text;
using System.Collections.Generic;
using NUnit.Framework;
public static class NUnitExtensions
{
public static void AssertAll<T>(this IEnumerable<T> objects, Action<T> test)
{
int total = 0;
int passed = 0;
int failed = 0;
int inconclusive = 0;
var sb = new StringBuilder();
foreach (var obj in objects)
{
total++;
try
{
test(obj);
passed++;
}
catch (InconclusiveException assertion)
{
inconclusive++;
string message = string.Format("INCONCLUSIVE: {0}: {1}", obj.ToString(), assertion.Message);
Console.WriteLine(message);
sb.AppendLine(message);
}
catch (AssertionException assertion)
{
failed++;
string message = string.Format("FAILED: {0}: {1}", obj.ToString(), assertion.Message);
Console.WriteLine(message);
sb.AppendLine(message);
}
}
if (passed != total)
{
string details = sb.ToString();
string message = string.Format("{0} of {1} tests passed; {2} inconclusive\n{3}", passed, total, inconclusive, details);
if (failed == 0)
{
Assert.Inconclusive(message);
}
else
{
Assert.AreEqual(total, passed, message);
}
}
}
}
You can use [TestCase()] attribute if a simple hard coded list of IDs.
[Test]
[TestCase(1234)]
[TestCase(5678)]
[TestCase(7654)]
public void TestSelect(int id)
{
DataTable old = Database.call("old_stored_proc", id);
DataTable new_ = Database.call("new_stored_proc", id);
Assert.AreEqual(old.Rows[0]["column"], new_.Rows[0]["column"]);
}
This will generate three separate tests for each ID and whatever nunit test runner you use will display pass/fail counts.
If need to generate a dynamic list of IDs then recommend using [TestCaseSource()] attribute.

Categories

Resources