?>
Jul
07
Filed Under (General, Updates) by Ryan Christiansen on 07-07-2008

It is not my intention to discredit FlexUnit’s decision to diverge it’s implementation from other testing frameworks, but rather to ensure that FUnit is firmly planted in what the testing community considers the de facto standard.

I will cite JUnit and NUnit as references for xUnit best practice. These frameworks are long established and widely adopted tools for unit-testing in the Java and .NET languages. The discrepancy between JUnit/NUnit and FlexUnit can be summarized as follows:

JUnit ‘assertEquals‘ / NUnit ‘areEqual‘ assert value equality.
FlexUnit ‘assertEquals‘ asserts reference equality.

When evaluating equality of value types such as Boolean, String, Number, etc. the behavior will be similar in most cases (we’ll outline these differences later). Test outcome for Object and Array assertions, however, may be drastically different between FlexUnit and other xUnit frameworks.

Important Correction: Since posting this article I’ve discovered that the JUnit method overload Assert.assertEquals(object[], object[]) has been deprecated and replaced by Assert.assertArrayEquals(object[], object[]). Variance between JUnit and NUnit may indicate that minor inconsistencies exist between testing frameworks as a whole and is not limited to FlexUnit alone. Further discussions on this topic and how it pertains to FUnit will continue here.

The following array equality assertion in JUnit will pass.
String[] array1 = { "one", "two", "three" };
String[] array2 = { "one", "two", "three" };
Assert.assertArrayEquals(array1, array2);
The following array equality assertion in NUnit will pass.
String[] array1 = { "one", "two", "three" };
String[] array2 = { "one", "two", "three" };
Assert.assertEquals(array1, array2);
The following array equality assertion in FlexUnit will fail.
var array1:Array = [ "one", "two", "three" ];
var array2:Array = [ "one", "two", "three" ];
Assert.assertEquals(array1, array2);

The intent of ‘assertEquals’ according to xUnit convention is to ensure that the value of two objects are identical, not that they reference the same object. A second assertion type ‘assertSame’ exists in JUnit (‘areSame’ for NUnit) to ensure that two objects share the same memory reference.

There are 3 possible reasons that may have lead FlexUnit developers to change the assertEquals implementation.

  • Inconsistencies between the ActionScript Object class and other languages.
  • Existence of two Flash equality types; equals (==) and strict equals (===).
  • Flash developer expectations and implied meaning of ‘assertEquals’.

Relevant Language Differences Between ActionScript and Java and .NET

The primary difference between the ActionScript Object definition and it’s Java/.NET counterparts is the absence of an Object.equals() method. All Java/.NET objects inherit from or override this method. Unfortunately, there is no ActionScript equivalent for member-wise equality comparison.

Object.equals() plays a crucial role in the ‘assertEquals’ implementation.

Note the JUnit source code for ‘assertEquals’ here:
static public void assertEquals(String message, Object expected, Object actual) {
	if (expected == null && actual == null)
		return;
	if (expected != null && expected.equals(actual))
		return;
	failNotEquals(message, expected, actual);
}

Standard Equality Vs. Strict Equality

It is important to note here that ‘standard equality’ (==) is a looser form of equality that does not exist in Java/.NET. These languages use what Flash considers ‘strict equality’ (===). Behavioral differences between these types become apparent when evaluating equality of value types (Boolean, String, Number, etc.).

The following equality assertion in JUnit (or NUnit) will fail.
int value1 = 5;
String value2 = "5";
Assert.assertEquals(value1, value2);
The following equality assertion in FlexUnit will pass.
var value1:int = 5;
var value2:String= "5";
Assert.assertEquals(value1, value2);

According to the Flash Language Reference:

The strict equality (===) operator differs from the equality (==) operator in only two ways:

  • The strict equality operator performs automatic data conversion only for the number types (Number, int, and uint), whereas the equality operator performs automatic data conversion for all primitive data types.
  • When comparing null and undefined, the strict equality operator returns false.

In other words, ‘standard equality’ does not enforce type equality of value types. This is inconsistent with other strong-typed languages.

User Expectation

Admittedly, my initial impressions of ‘assertEquals’ is that i would perform reference comparison. If you say “Assert that value1 and value2 are equal.”, it would be easy to visualize “value1 == value2″. Since this is not what will be executed, this could be viewed as misleading.

Proposed Solution

The FUnit framework was designed to be intuitive. It was also designed to be ubiquitous with other frameworks. I don’t want developers of JUnit, NUnit, or FUnit tests to have to change their logic just because they switch languages. The less you have to think about the tools, the more focused you can be on using them.

I would opt for a stronger more consistent xUnit form of equality assertion. This however might require minor changes when migrating tests from FlexUnit implementations. I would also create a secondary LegacyAssert class that would perform identically to it’s FlexUnit counterpart. This would allow the developer to choose between xUnit convention or a more familiar FlexUnit behavior (or both in combination). This will ultimately empower the developer to be more explicit in their unit-testing.

FUnit Assert API
function areEqual( expected:Object, actual:Object ) : void
function areSame( expected:Object, actual:Object ) : void
FUnit LegacyAssert API
function areEqual( expected:Object, actual:Object ) : void
function areStrictEqual( expected:Object, actual:Object ) : void
Which 'assertEquals' implementation works best for you?
View Results


Post a comment

Name: 
Email: 
URL: 
Comments: 

.