xUnit tests failing to Assert.Equal two equal values - c#

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!

Related

Problems with Hashing (with BinaryFormatter) with class object containing negative number

Basically, we have a number of POCO's which we convert to hash values. The purpose is to use the hash string as the unique identifer for that particular object. If we find another object with the same values, the hash string should is the same, etc.
However, we have come across a problem where the hash results appears to be the same if the integer field contains a negative number.
Below is our extension method to Serialize and hash the given object: -
public static string Serialize<T>(this T classObject) where T : class
{
var formatter = new BinaryFormatter();
using (var stream = new MemoryStream())
{
formatter.Serialize(stream, classObject);
stream.Position = 0;
var sr = new StreamReader(stream);
var text = sr.ReadToEnd();
return text;
}
}
public static string ToHash(this string str)
{
var bytes = Encoding.UTF8.GetBytes(str);
var md5 = new SHA256CryptoServiceProvider();
byte[] result = md5.ComputeHash(bytes);
return Convert.ToBase64String(result);
}
In order to demonstrate this problem, I have created a sample class: -
[Serializable]
public class TestClass
{
public string StringA;
public string StringB;
public int? Created;
}
Here is my test code...
var testZero = new TestClass
{
StringA = "String A",
StringB = "String B",
Created = 0,
};
var testNull = new TestClass
{
StringA = "String A",
StringB = "String B",
Created = null,
};
var testMinusOne = new TestClass
{
StringA = "String A",
StringB = "String B",
Created = -1
};
var testMinusTwo = new TestClass
{
StringA = "String A",
StringB = "String B",
Created = -2
};
var testMinusThree = new TestClass
{
StringA = "String A",
StringB = "String B",
Created = -3
};
var testMinusOneHundred = new TestClass
{
StringA = "String A",
StringB = "String B",
Created = -100
};
var testOneHundred = new TestClass
{
StringA = "String A",
StringB = "String B",
Created = 100
};
var rHashZero = testZero.Serialize().ToHash();
var rHashNull = testNull.Serialize().ToHash();
var rHashMinusOne = testMinusOne.Serialize().ToHash();
var rHashMinusTwo = testMinusTwo.Serialize().ToHash();
var rHashMinusThree = testMinusThree.Serialize().ToHash();
var rHashMinusHundred = testMinusOneHundred.Serialize().ToHash();
var rHashHundred = testOneHundred.Serialize().ToHash();
The variables (at the end) contain the following values :-
rHashZero = "aFJROVaqEbWneZJkDnB00qkxPf4TF/w+22VhgR+4nHU=";
rHashNull = "0/tsIhQzZK+Jirnee1o8QTjU8G1hOB/ODdnr2UipBPU=";
rHashMinusOne = "Q5xsfYpm/Em2vw19N9283Gq9fUoI7WxN+ip61S/m3h0=";
rHashMinusTwo = "Q5xsfYpm/Em2vw19N9283Gq9fUoI7WxN+ip61S/m3h0=";
rHashMinusThree = "Q5xsfYpm/Em2vw19N9283Gq9fUoI7WxN+ip61S/m3h0=";
rHashMinusHundred = "Q5xsfYpm/Em2vw19N9283Gq9fUoI7WxN+ip61S/m3h0=";
rHashHundred = "3q6S9vZPujnSc5b2YAbtD61Dj+4B5ZzoILnL1lH291M=";
My main question is why are the objects with the negative integer value all return the same hash string? Despite StringA and StringB being the same, the Created field is not the same.
If anyone can explain this to me - that would be great. Also, Is there a solution?
I have also tested this by removing the nullable (?) from the int, but the results are the same.
PS -- I am convinced I came across a site which mentioned something about negative numbers, but was convinced it was 'fixed' in a later .net release. This is going back a while now so that site may no longer exist.
I tried to find info about this on the internet but no luck. Maybe I am not using correct words on a search engine?
Any help is appreciated.
The problem is that you're reading the result of result of the BinaryFormatter as if it were a properly formed UTF-16 string. It is not.
Unicode is not a simple 1:1 mapping between bytes and characters, unlike ASCII. This means that you managed to malform the data. It's obvious when you print out the string that results from the SerializeMethod:
For the 100 case, I get
□□□□□����□□□□□□□□□□□□□Cquery_rtzxks, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null□□□□□□UserQuery+TestClass□□□□□StringA□StringB□Created□□□□System.Int32□□□□□□□□□□String A□□□□□□String B□□d□□□□
While for -100, I get
□□□□□����□□□□□□□□□□□□□Cquery_rtzxks, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null□□□□□□UserQuery+TestClass□□□□□StringA□StringB□Created□□□□System.Int32□□□□□□□□□□String A□□□□□□String B□□����□
(the namespaces etc. are from LINQPad. The important point are the values like □����□ right there at the end)
It should be rather obvious that your "conversion" is throwing away tons of data. Due to the way the memory is organized, this makes your code appear to work sometimes, but that is the exception - it's just that by chance, some values of the serialized integer happen to be proper unicode characters, which would then result in a different string - if they are not proper characters, they will be the same.
The solution is simple - don't pretend random byte sequences are valid UTF-16 strings. Just pass the byte[] you get from stream.ToArray() and be done with it. If you absolutely want string for some reason, use Convert.ToBase64String.
Also, since this isn't clear in your question, do not treat hashes as unique - they are not. The relation is "if the values are the same, the hashes must be the same", but not "if the hashes are the same, the values must be the same". So in a way, your hashing function is just fine, it doesn't violate this relation. It's not all that useful either, though.
So, why is this giving you trouble for negative numbers specially? The short answer is "it doesn't". This has to do with how numbers are saved in BinaryFormatter - negative values are really large, for example, -1 would be 0xFFFFFFFF. Those are turned to �, of course, because there's no code-point mappings. On the other hand, the test positive values you've used are relatively small, and have a good chance of hitting ASCII-like code points. For example, the value of 100 is 0x64000000 - and 0x64 is d, which is fine. However, for example, 65535 and 65532 will have the same "string" representation, because both 0xFFFF and 0xFFFC are incorrect code points, and will be resolved into �. When you then feed this to your hashing function, the two input strings will be exactly the same. For negative numbers, -3 and -65532 will produce different hashes, for example.
Thanks for everyones answer. I have pretty much gone the direction of using stream.ToArray() and Convert.ToBase64 to return the string. The results look promising at this time.
I apologise that this question is causing lots of "wtf" and I understand the downvote with more likely to follow! I am not a hardcore C# developer and I am working on a large project at this time. I was not suppose to be on this, either! Trying to piece this project together was a bit of a challenge especially when a half-finished change involved negative numbers.
Thanks again.

Array.ToString() returning System.Char[] c#

Im making a hangman game, at the start of the game the word that the player must guess is printed as stars. I have just started making it again after attempting to write it once and just having messy code that i couldn't bug fix. So I decided it best to write it again. The only problem is, when i try to get my array to print out by using array.ToString(); it just returns System.char[]. See below.
code:
class Program
{
static void Main(string[] args)
{
string PlayerOneWord;
string PlayerTwoGuess;
int lives = 5;
Console.WriteLine("Welcome to hangman!\n PLayer one, Please enter the word which player Two needs to guess!");
PlayerOneWord = Console.ReadLine().ToLower();
var stars = new char[PlayerOneWord.Length];
for (int i = 0; i < stars.Length ; i++)
{
stars[i] = '*';
}
string StarString = stars.ToString();
Console.Write("Word to Guess: {0}" , StarString);
Console.ReadLine();
}
}
output:
The output should say Word to guess: Hello.
Please will someone explain why this is happening as its not the first time I have run into this problem.
Calling ToString on a simple array only returns "T[]" regardless what the type T is. It doesn't have any special handling for char[].
To convert a char[] to string you can use:
string s = new string(charArray);
But for your concrete problem there is an even simpler solution:
string stars = new string('*', PlayerOneWord.Length);
The constructor public String(char c, int count) repeats c count times.
The variable stars is an array of chars. This is the reason you get this error. As it is stated in MSDN
Returns a string that represents the current object.
In order you get a string from the characters in this array, you could use this:
Console.Write("Word to Guess: {0}" , new String(stars));
The correct way to do this would be:
string StarString = new string(stars);
ToString() calls the standard implementation of the Array-class's ToString-method which is the same for all Arrays and similarily to object only returns the fully qualified class name.
Try this code:
static string ConvertCharArr2Str(char[] chs)
{
var s = "";
foreach (var c in chs)
{
s += c;
}
return s;
}

Freeze enum value in AutoFixture

We have an enum:
enum Letters
{
A,
B,
C,
D,
E
}
When I try:
var frozenLetter = fixture.Freeze(Letters.D);
Strangely, frozenLetter == A.
var letter = fixture.Create<Letters>();
var anotherLetter = fixture.Create<Letters>();
Letter and anotherLetter both equal A, so the Letters type has been frozen, but to the first constant in the enum rather than the one specified.
Is there a way to freeze an enum to the constant I wish?
Freeze Inject and Register are slightly different.
Use Inject for the described behavior, as the following test demonstrates:
[Fact]
public void Test()
{
var fixture = new Fixture();
var expected = Letters.D;
fixture.Inject(expected);
var letter = fixture.Create<Letters>();
var anotherLetter = fixture.Create<Letters>();
Assert.Equal(expected, letter);
Assert.Equal(expected, anotherLetter);
}
The problem with the question's sample code is that the parameter (seed) isn't used as the frozen value.

Unit testing in C# how to?

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.

Signed int array typecast C#

When I run the following code:
public int[] finalResult = new int[dimension];
public float[] calculatedValue = new float[dimension];
.....
.....
finalResult[i] = (int) Math.Floor(calculatedValue[i]);
Console.WriteLine( "calculated:" + calculatedValue[i]
+ " final:" + finalResult[i]
+ " test: " +(int) Math.Floor(calculatedValue[i]));
The output is:
calculated:-0.02043936 final:0 test:-1
Why is "final" different from "test" when they are generated from exactly the same code? Which one is wrong, and why?
even simpler, and smaller fragment
finalResult[i]=(int)Math.Floor(-3.0002);
Console.WriteLine( "final: "+ finalResult[i]+ " test:" +(int)Math.Floor(-3.0002));
output
final:0 test:-4
The remaining of the code is irrevelant as below proves
I tried the following lastly,
public int[] junkArray = new int[dimension];
junkArray[i]=(int)Math.Floor(-3.0002); //Junk Array is only assigned here in whole code
Console.WriteLine( "final: "+ (int) junkArray[i]+ " test:" +(int)Math.Floor(-3.0002));
I get output as final:0 test:-4
Here's what I think is actually happening. Bear in mind that I'm making assumptions here, since the code you've provided doesn't compile and when I try to adapt it I always get the correct results that I'd expect. I've thus tried to think of ways to produce the results you're getting by making a deliberate mistake:
using System;
namespace ConsoleApplication1
{
class Program
{
private static int dimension = 1;
public static int[] junkArray = new int[dimension];
static void Main(string[] args)
{
Method1();
Method2();
}
static void Method1()
{
int i = 0;
junkArray[i] = (int)Math.Floor(-3.0002);
}
static void Method2()
{
int i = 0;
int[] junkArray = new int[dimension];
Console.WriteLine("final: " + (int)junkArray[i] + " test:" + (int)Math.Floor(-3.0002));
}
}
}
This produces the results you're seeing:
final:0 test:-4
I've split the code into two methods, one method which is doing the "calculation" and another which does the "presentation". However, for some reason (lack of caffeine, whatever) my second method also declares an array variable that is hiding/shadowing the field that contains our computed results. This isn't illegal, but it means that when I read from junkArray in my Console.WriteLine method call I'm reading from a different junkArray to the one I wrote my results to earlier.
This may not be what's happening, but it's a possibility and without seeing your actual code it's the best guess I can offer. Have a look and make absolutely sure that the array you're reading from is definitely the same array you wrote your results to, rather than a second array that's "shadowing" the first.
If I test the code
var final = new int[1];
var calc = new[] { -0.02043936f };
final[0] = (int)Math.Floor(calc[0]);
Console.WriteLine(
"calc:{0} final:{1} test:{2}",
calc[0],
final[0],
(int)Math.Floor(calc[0]));
unsuprisingly I get the output
calc:-0.02043936 final:-1 test:-1
So, something else is wrong with your code.
There are two things happening here
First - -0.02043936 is a calculated value
Now you are applying math.floor on it. What it will do is, it will floor the value and return a double which will again be a significantly small number.
Now you are casting it to an integer. while doing so, as it is more close to zero, it will turn it out to zero.
To prove this, make the calculated value -0.62043936 or something like and you will get -1 as per your expectation

Categories

Resources