Rhino Mocks : How to match array arguments in an expectation? - c#

Again at the Rhino Mocks Noob Wall
mockUI.Expect( x => x.Update( new Frame[] {Frame.MakeIncompleteFrame(1, 5)} ) );
This is the exact argument that I need to match. Via trace statements, I have verified that is the actual output as well i.e. the code behaves as intended but the test disagrees. RhinoMocks responds with
TestBowlingScorer.TestGamePresenter.TestStart:
Rhino.Mocks.Exceptions.ExpectationViolationException : IScoreObserver.Update([Frame# 1, Score = 0 Rolls [ 5, PENDING, ]]); Expected #1, Actual #0.
A Frame object contains few properties but doesn't override Equals() yet (overridden ToString() seen above). Update receives an array of Frames;
How do I setup this expectation? I see an Is.Matching constraint.. not sure how to use it or rather am concerned with the verbose nature of it.
I have a helper NUnit style custom Assert
public static void AssertFramesAreEqual(Frame[] expectedFrames, Frame[] actualFrames)
{
// loop over both collections
// compare attributes
}

#Gishu,
Yeah, that's it. I just also learned about the Arg<> static class which should allow you to do something like this:
mockUI.Expect( x => x.Update(Arg<Frame[]>
.Matches(fs=>HelperPredicates.CheckFrames ( expected, fs)) ));
There is also the Arg<>.List configuration starting point which I have not explored yet but might be even better for what you want

Verified works.. don't know if this is THE RhinoMocks way
var expectedFrames = new Frame[] { Frame.MakeIncompleteFrame(1, 5) };
mockUI.Expect( x => x.Update(null) )
.IgnoreArguments()
.Constraints( Is.Matching<Frame[]>( frames => HelperPredicates.CheckFramesMatch(expectedFrames, frames) ) );
The helper predicate is just a function that returns a boolean value - True on an exact match else false.
public static bool CheckFramesMatch(Frame[] expectedFrames, Frame[] actualFrames)
{
// return false if array lengths differ
// loop over corresponding elements
// return false if any attribute differs
// return true
}

Related

verify method was called with array, with clear failure message

I have a method I verify as part of my test. One of its parameters is an array that can potentially be very large (over 100 bytes). How can I easily find the point of failure, without needing to go through some serious debugging?
The tested line is:
mockDependeny.verify(x=>x.callMethod(expectedModel, expectedModel.Length, It.IsAny<otherKindOfParam>()));
expectedModel is passed in the method (a theory) and is an array.
One set of data/expected in the theory works, but the next one says that it failed. The message it gives me is not very helpful -
Expected invocation on the mock at least once, but was never performed: x=>x.callMethod([1,2,3,4,5,6,7,8,9,10,...], 175 , It.IsAny())
Perfomed invocations:
Mock(x): MyDependency.callMethod([1,2,3,4,5,6,7,8,9,10,...], 175 , instanceOfOtherParam)
All I can glean from this is that somewhere in the next n-10 items in the array, there is something that does not match up ( the first ten items are the same, the overall length is the same)
Is there a way to get better feedback from the test, so I do not have to debug and manually compare the contents of the expceted vs actual arrays?
Replace the expectedModel array parameter with an It.Is<> and implement anything you want. E.g.:
mockDependency.Verify(x => x.callMethod(It.Is<byte[]>(m => VerifyThisEnumerableParam(m, expectedModel)), expectedModel.Length, It.IsAny<object>()));
...
private bool VerifyThisEnumerableParam<T>(IEnumerable<T> received, IEnumerable<T> expected)
{
if (received != expected)
{
var receivedArray = received.ToArray();
var expectedArray = expected.ToArray();
if (receivedArray.Length != expectedArray.Length ||
receivedArray.Where((t, idx) => !Object.Equals(t, expectedArray[idx])).Any())
{
// now let's visualize the two thing
throw new AssertFailedException($#"received != expected
expected: {String.Join(", ", expected.Select(t=>t.ToString()))}
received: {String.Join(", ", received.Select(t => t.ToString()))}");
}
}
return true;
}
The above isn't fool proof (no additional null, etc. checks), but hope you got the idea. If you prefer just the first differing index or something else just implement it in the method.

Is it possible to assert the existence of one or more elements in an array without a for loop?

I am testing a function with XUnit. While the test correctly does the job of identifying the existence of "System.DateTime" in a returned Type[] array, I have to do so by looping through the array. (Why test the existence of a DateTime property I already know of? Because I am learning TDD by playing with some code I'm already familiar with.)
Is there an Assert function that can confirm the existence of an element in array? I am asking question because, while it works, I can't help but wonder if there is any more efficient or compact way of doing this besides looping through the array.
I was hoping there was an undocumented feature in Assert that I could take advantage of.
/// <summary>
/// This tests the "GetPropertyTypes(PropertyInfo[] properties)" function to
/// confirm that any DateTime properties in the "TestClass" are confirmed as existing.
/// </summary>
[Fact]
public void ConfirmDateTimePropertiesInModelExist()
{
// Arrange
PropertyInfo[] propertiesInfos = typeof(TestClass).GetProperties();
int dateTimeCount = 0;
// Act
// The names array the list of property types in "TestClass"
Type[] propertyTypes = ExportToExcelUtilities.GetPropertyTypes(propertiesInfos);
for (int i = 0; i < propertyTypes.Length; i++)
if (propertyTypes[i] == typeof(DateTime))
dateTimeCount++;
// Assert
// Assert that the names array contains one or more "System.DateTime" properties.
Assert.True(dateTimeCount>0,
"Existing DateTime properties were not identified in the class.");
}
LINQ makes quick work of this:
Assert.True(propertyTypes.Any(n => n == typeof(DateTime)))
You don't necessarily need custom assertions since you can use a standard array commands within your Assert.True().
For example, you could use Array.FindIndex().
var index = Array.FindIndex(propertyTypes, t => t == typeof(DateTime));
If the index is greater than -1 then an item was found. So to use this in an assertion:
Assert.True(
Array.FindIndex(propertyTypes, t => t == typeof(DateTime)) > -1,
"Existing DateTime properties were not identified in the class."
);

Assert that value is equal to any of a collection of expected values

Does NUnit provide a constraint to find whether the actual value is the element of a given enumerable or array, in other words, that it is equal to any of multiple expected values? Something like:
Assert.That(actual, Is.EqualToAnyOf(new[] { 1, 2, 3 }))
That is, to point out, the actual is a single value. I expect the value to be either 1, 2, or 3. The assertion
Assert.That(actual, Contains.Element(expected))
checks logically the same, but it is the opposite intention: Here we have a collection of actual values and expect one value to be in it.
Furthermore, I found these but they all don't fit:
Assert.That(actual, Is.EqualTo(expected)) // only allows one value
Assert.That(actual, Is.InRange(start, end)) // only works for consecutive numbers
Assert.That(actual, Is.SubsetOf(expected)) // only works if actual is an enumerable
Assert.That(expected.Contains(actual)) // meaningless "expected: true but was: false" message
CollectionAssert should be what you need if I am not overlooking something. It is as simple as:
CollectionAssert.Contains(IEnumerable expected, object actual);
However, there seems to be several ways to achieve your goal, such as:
[Test]
public void CollectionContains()
{
var expected = new List<int> { 0, 1, 2, 3, 5 };
var actual = 5;
CollectionAssert.Contains(expected, actual);
Assert.That(expected, Contains.Item(actual));
}
Above assertions should basically assert the same and could be used interchangeably.
Edit:
Question was modified, stating that Assert.That(expected, Contains.Item(actual)); is not valid even though it logically tests the same thing.
There is a way to do this built in to NUnit, using the Or constraint:
Assert.That(actual, Is.EqualTo(1).Or.EqualTo(2).Or.EqualTo(3))
If your list is more dynamic, you can build your list of Ors like this:
var expected = new[] { 1, 2, 3 };
var constraints = Is.EqualTo(expected[0]);
for(var i = 1; i < expected.Length; i++)
constraints = constraints.Or.EqualTo(expected[i]);
Assert.That(actual, constraints);
That latter answer doesn't read as well in the fluid syntax, but does achieve the dynamic building of or constraints. You could probably wrap that in a custom constraint as patrick-quirk demonstrated in order to achieve a more readbale fluid syntax, but that's up to you.
I know this is an old question, bu I have a maybe better (and native) suggestion.
With NUnit 3.x (I'm on 3.10.1) you can use Is.AnyOf:
Assert.That(
actualValue,
Is.AnyOf(expectedValue1, expectedValue2, expectedValue3),
"My error message");
The only way I could see to accomplish this is by creating your own constraint. It's pretty straightforward to do though.
The constraint class itself:
public class OneOfValuesConstraint : EqualConstraint
{
readonly ICollection expected;
NUnitEqualityComparer comparer = new NUnitEqualityComparer();
public OneOfValuesConstraint(ICollection expected)
: base(expected)
{
this.expected = expected;
}
public override bool Matches(object actual)
{
// set the base class value so it appears in the error message
this.actual = actual;
Tolerance tolerance = Tolerance.Empty;
// Loop through the expected values and return true on first match
foreach (object value in expected)
if (comparer.AreEqual(value, actual, ref tolerance))
return true;
// No matches, return false
return false;
}
// Overridden for a cleaner error message (contributed by #chiccodoro)
public override void WriteMessageTo(MessageWriter writer)
{
writer.DisplayDifferences(this);
}
public override void WriteDescriptionTo(MessageWriter writer)
{
writer.Write("either of ");
writer.WriteExpectedValue(this.expected);
}
}
And to make it fluent, create a static method to wrap it (contributed by #chicodorro):
public static class IsEqual
{
public static OneOfValuesConstraint ToAny(ICollection expected)
{
return new OneOfValuesConstraint(expected);
}
}
Then to use it:
int[] expectedValues = new[] { 0, 1, 2 };
Assert.That(6, IsEqual.ToAny(expectedValues));
Fails with the message:
Expected: either of < 0, 1, 2 >
But was: 6

Added functionality broke my tests - very simple logic too

I have code similar to this:
public List<string> Expected = new List<string>();
public int SpecifiedID;
public DataIn(int ID, string Value)
{
Expected.Add(Value);
//if (ID == SpecifiedID)
//Expected.Clear();
//Need to add this but my tests that do something like
//CollectionAssert.AreEqual(new[] { "2", "4", "6", "8" }, logic.Expected);
//all fail as Expected is empty.
}
//Example Test
[Test]
public void NewTestFunction()
{
MyClass logic = new MyClass();
logic.SpecifiedID = 4;
logic.DataIn(1,"2");
logic.DataIn(2,"4");
logic.DataIn(3,"6");
logic.DataIn(4,"8");
//This will FAIL if Expected.Clear is added in the class.
CollectionAssert.AreEqual(new[] { "2", "4", "6", "8" }, logic.Expected);
}
This is simplified a lot however I have tests that check the validity of the Expected contents when DataIn is called. However I now have realised I have to clear Expected after every DataIn call. This has broken my tests obviously as there is nothing in it to assert against.
Any suggestions on how to keep the tests that validate the contents but also allow me to empty the collection?
The answer is simple - your code does not pass your test. I.e. it does not behave as expected (you describe expected behavior in your test). So, code should change - remove call to Expected.Clear(). Or think about what you expect from your code.
UPDATE (for case when expectations changes):
public void ShoulHaveAllDataInWhenIdIsNotSpecifiedID()
{
MyClass logic = new MyClass();
logic.SpecifiedID = 3;
logic.DataIn(1,"2");
logic.DataIn(2,"4");
CollectionAssert.AreEqual(new[] { "2", "4" }, logic.Expected);
}
[Test]
public void ShoulClearAllDataWhenSpecifiedIDPassed()
{
MyClass logic = new MyClass();
logic.SpecifiedID = 3;
logic.DataIn(1,"2");
logic.DataIn(2,"4");
logic.DataIn(3,"6");
CollectionAssert.AreEqual(new[] { }, logic.Expected);
}
Also consider doing behavior testing instead of state testing. By providing mocks to your class you can check how it interacts with them. I.e. check what data passed to your class dependency.
Initialization to known good state should be part of your test/class setup method. From your description, though, it seems like you may have too much coupling between your tests or that your tests are testing too much at one time. Each test, with appropriate set up, should be independent and ideally able to run in parallel. Typically this means that each is running against a different instance of the class under test and you don't have dependencies on global data, or at least those dependencies are read-only so you can set it once for all tests.
When the SpecifiedID is matched everything has to be cleared
This is one test. Instantiate your object. Give it a SpecifiedId of X. Call DataIn() on it with Y as a first parameter and then with X as a first parameter. Assert that Expected is empty. Simple.
when the next call is made it starts adding data to it again ready for
validation
This is another test. Instantiate your object. Give it a SpecifiedId of X. Repeatedly call DataIn() on it never using X as an ID. Assert that Expected contains the passed values. Simple.
Two requirements, two tests. Really, I can't see what's the big deal here.
Why do not just change test function. Create a new test function:
[Test]
public void NewTestFunction()
{
Data("Bla");
//Test for something
Expected.Clear();
}
If this is not what you're asking for, please clarify.

How does Assert.AreEqual determine equality between two generic IEnumerables?

I have a unit test to check whether a method returns the correct IEnumerable. The method builds the enumerable using yield return. The class that it is an enumerable of is below:
enum TokenType
{
NUMBER,
COMMAND,
ARITHMETIC,
}
internal class Token
{
public TokenType type { get; set; }
public string text { get; set; }
public static bool operator == (Token lh, Token rh) { return (lh.type == rh.type) && (lh.text == rh.text); }
public static bool operator != (Token lh, Token rh) { return !(lh == rh); }
public override int GetHashCode()
{
return text.GetHashCode() % type.GetHashCode();
}
public override bool Equals(object obj)
{
return this == (Token)obj;
}
}
This is the relevant part of the method:
foreach (var lookup in REGEX_MAPPING)
{
if (lookup.re.IsMatch(s))
{
yield return new Token { type = lookup.type, text = s };
break;
}
}
If I store the result of this method in actual, make another enumerable expected, and compare them like this...
Assert.AreEqual(expected, actual);
..., the assertion fails.
I wrote an extension method for IEnumerable that is similar to Python's zip function (it combines two IEnumerables into a set of pairs) and tried this:
foreach(Token[] t in expected.zip(actual))
{
Assert.AreEqual(t[0], t[1]);
}
It worked! So what is the difference between these two Assert.AreEquals?
Found it:
Assert.IsTrue(expected.SequenceEqual(actual));
Have you considered using the CollectionAssert class instead...considering that it is intended to perform equality checks on collections?
Addendum:
If the 'collections' being compared are enumerations, then simply wrapping them with 'new List<T>(enumeration)' is the easiest way to perform the comparison. Constructing a new list causes some overhead of course, but in the context of a unit test this should not matter too much I hope?
Assert.AreEqual is going to compare the two objects at hand. IEnumerables are types in and of themselves, and provide a mechanism to iterate over some collection...but they are not actually that collection. Your original comparison compared two IEnumerables, which is a valid comparison...but not what you needed. You needed to compare what the two IEnumerables were intended to enumerate.
Here is how I compare two enumerables:
Assert.AreEqual(t1.Count(), t2.Count());
IEnumerator<Token> e1 = t1.GetEnumerator();
IEnumerator<Token> e2 = t2.GetEnumerator();
while (e1.MoveNext() && e2.MoveNext())
{
Assert.AreEqual(e1.Current, e2.Current);
}
I am not sure whether the above is less code than your .Zip method, but it is about as simple as it gets.
I think the simplest and clearest way to assert the equality you want is a combination of the answer by jerryjvl and comment on his post by MEMark - combine CollectionAssert.AreEqual with extension methods:
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
This gives richer error information than the SequenceEqual answer suggested by the OP (it will tell you which element was found that was unexpected). For example:
IEnumerable<string> expected = new List<string> { "a", "b" };
IEnumerable<string> actual = new List<string> { "a", "c" }; // mismatching second element
CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
// Helpful failure message!
// CollectionAssert.AreEqual failed. (Element at index 1 do not match.)
Assert.IsTrue(expected.SequenceEqual(actual));
// Mediocre failure message:
// Assert.IsTrue failed.
You'll be really pleased you did it this way if/when your test fails - sometimes you can even know what's wrong without having to break out the debugger - and hey you're doing TDD right, so you write a failing test first, right? ;-)
The error messages get even more helpful if you're using AreEquivalent to test for equivalence (order doesn't matter):
CollectionAssert.AreEquivalent(expected.ToList(), actual.ToList());
// really helpful error message!
// CollectionAssert.AreEquivalent failed. The expected collection contains 1
// occurrence(s) of <b>. The actual collection contains 0 occurrence(s).

Categories

Resources