What’s the deal with MbUnit

Consider the following code :

 

        [Test]

        public void StringFormatEqualsTest()

        {

            string firstString = string.Format(“{0}”, “test”);

            string secondString = string.Format(“{0}”, “test”);

 

            Assert.AreNotEqual(firstString, secondString); //test passes

        }

 

        [Test]

        public void StringEqualsTest()

        {

            string firstString = “test”;

            string secondString = “test”;

 

            Assert.AreNotEqual(firstString, secondString); //test fails

        }

 

Why does the first test (StringFormatEquals) pass ? In my opinion it shouldn’t. I raised a bug report on the mbunit site.

This behaviour doesn’t exist in nunit.  I’m just putting it out there because you do want your tests to reflect the thruth :) .

  1. My guess is for StringEqualsTest, the two string variables actually “point” to the same memory location. Therefore the two variables are truly equal.

    For StringFormatEqualsTest, the two variables are created dynamically, but are only equivalent. They don’t “point” to the same memory location and so are not “equal”. The question is whether or not the Assert.AreNotEqual test is looking for equality or equivalence.

  2. Kirk Jackson

    That is strange behaviour, it appears that AreEqual and AreNotEqual have differing behaviour — both times you’re getting the (object,object) overload of the method.

    AreNotEqual uses:
    if (expected == actual)

    AreEqual uses:
    !ObjectsEqual(expected, actual)

    which does:
    return expected.Equals(actual);

    So one does a reference equality, and the other does an Equals call.

    Kirk

  3. Ivan Porto Carrero

    I know why this happens :)
    It’s just a wrong behavior and I wanted to bring it to the attention of people.

  4. Alex Henderson

    Definitely incorrect behavior, obviously:

    Assert.AreNotEqual(x,y) == (!Assert.AreEqual(x,y))

    should be reciprocal, one fails when the other passes… in this case I suspect it doesn’t work that way.

    Still – string-interning related problems seem to trip people up quite often, like creating an untyped hashtable with string key parameters and then wondering why sometimes a lookup fails for “no apparent reason” ;o)

  5. Kirk is right. AreNotEqual is comparing references and AreEqual is comparing values.

    The reason AreNotEqual is correctly failing in StringEqualsTest is because of the way the .NET framework manages the string intern pool. All string literals come from the string intern pool.

    In StringEqualsTest, firstString and secondString are the same reference, so AreNotEqual correctly fails when comparing references.

    In StringFormatEqualsTest, string.Format creates a new reference to each string – even if the string is already in the string intern pool, so AreNotEqual incorrectly passes because the two references are different, even though they contain the same value.

    The following change would make StringFormatEqualsTest work with MBUnit as it forces firstString and secondString to use references from the intern pool. MBUnit seems to be relying on this in the AreNotEqual test.

    string firstString = string.Intern(string.Format(“{0}”, “test”));
    string secondString = string.Intern(string.Format(“{0}”, “test”));

    Assert.AreNotEqual(firstString, secondString); //test fails

  6. Kirk Jackson

    I’d probably fix it by making specific overrides for (string, string), so that you don’t end up with operator==(object,object) being called in the bowels, since that won’t end up calling strings operator==(string,string) method.

    Also, I’d probably change the internals of the AreEqual and AreNotEqual to use the same logic, but negating one another.

    Kirk

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>