Why can’t I use Assert.Equals?

Ever wondered why you cannot use Assert.Equals() for both Nunit and MSTest. If you have not then maybe as a start you need to be aware that you cannot use this method. Instead you would use Assert.AreEqual() to compare two objects for equality.

The reason here is very simple. Like any class the Assert class is inheriting from System.Object that has a public virtual Equals method meant to check if a given object is equal to the current object. Therefor calling that equals method would be a mistake as in a unit test you would instead to compare two objects that have nothing to do with the Assert class. As a result Nunit and MSTest both chose to provide a method Assert.AreEqual for that purpose.

Furthermore to ensure that you do not use the Equals method by mistake they have decided to throw Exceptions to warn you if you do use this by mistake.

Nunit Implementation:


        [EditorBrowsable(EditorBrowsableState.Never)]
        public static new bool Equals(object a, object b)
        {
            // TODO: This should probably be InvalidOperationException
            throw new AssertionException("Assert.Equals should not be used for Assertions");
        }

MSTest Implementation:


        public new static bool Equals(object objA, object objB)
        {
            Assert.Fail((string)FrameworkMessages.DoNotUseAssertEquals);
            return false;
        }

Advertisements

Can you interact with user in current context?

Ever had to write a generic implementation of a feature that should interact with a user if possible otherwise use an alternative.

An example would be an exception handling manager that would show a message box to the user for certain exception if there is a U.I say in a WPF app else log to the event viewer say in a Windows service. Fortunately there is an easy way to find out if the current context is interactive as follows:

Environment.UserInteractive

 

InternalsVisibleTo useful

One of the not so commonly usage attributes targeting assemblies is the InternalsVisibleTo attribute. This attribute declares that a given assembly will be given access to internal items in the assembly it is declared on.

This can be very useful with unit testing if you want to have access to internal items or in scenarios were you want to create a new assembly as a wrapper around one of your existing assemblies you may want to give it those privileges. A good place to stick this in is the AssemblyInfo.cs class with usage as shown below. By using this feature you create what can be called Friend libraries.

[assembly: InternalsVisibleTo("TargetAssembly, PublicKey=<key>")]

Multiple usings bundled

Interesting thing to note. While you can bundle multiple using together by nesting as shown in example 1, you can totally avoid the nesting by removing some braces and still have the same effect as shown in example 2. You may expect that the first object will immediately be disposed before the next line executes but this is syntactic sugar to work as the first example.

Example 1:


            using (var a = new Test())
            {
                using (var b = new Test())
                {

                }
            }

Example 2:


            using (var a = new Test())
            using (var b = new Test())
            {

            }

 

Make custom types support object initializers

In C# you can easily make your custom types support object initializers by doing two things

  • Implement IEnumerable<T>
  • Add a public void method called Add accepting the type desired intializer type as a parameter

Example:

Implement IEnumerable<T>


    public class ProgrammingLanguage:IEnumerable&lt;string&gt;
    {
        private readonly HashSet&lt;string&gt; supportedTypes = new HashSet&lt;string&gt;();

        public IEnumerator&lt;string&gt; GetEnumerator()
        {
            return this.supportedTypes.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }

Add the Add method


        public void Add(string name)
        {

        }

Sample usage:


            var javaScript = new ProgrammingLanguage{&quot;int&quot;,&quot;bool&quot;,&quot;string&quot;};

Update:

Interestingly for an object to be enumerable and say qualify to be iterated by foreach it does not have implement IEnumerable. Instead it simply has to have a public method GetEnumerator that returns a type with a public bool MoveNext and public void Current. The compiler does not actually check to see if the interface is implemented.

Frustration with System.IO.Packaging.Package

I have had a very frustrating time with making use of Packages to zip files in .NET. Below is a question I posted on stackoverflow together with the hack I used to make it go away fast.

I am making use of the System.IO.Packagng.Package class to zip files. It is possible to have multiple instances of my application running at the same time with files being read and saved. When working with small files all seems fine, however when large files are involved if two instances of the application save at the same time I get an exception with the message Store must be open for this operation with the stack trace shown below.

From my understanding when working with the packages for files <10mb the data is stored in some memory stream but when it is >10mb internally that will switch to IsolatedStorage. With that in mind I was able to find that even though these are multiple instances running they all get the same isolated storage location resolved and I believe that is were the problem comes in. I was able to find a hack to force each instance to resolve to a different location using the following code:


            var s_DirUserField = typeof(IsolatedStorageFile).GetField("s_RootDirUser", BindingFlags.NonPublic | BindingFlags.Static);
            s_DirUserField.SetValue(null, @"&amp;lt;unique location in IsolatedStorage&amp;gt;");

Even though that made the problem go away I do not like it one bit. Please help in figuring out how to fix this problem elegantly. On further research I found out that IsolatedStorage is not even meant to be used with multiple threads, which gets me to wonder why it was then an option when dealing with Packages.

   at System.IO.IsolatedStorage.IsolatedStorageFileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, IsolatedStorageFile isf)
   at MS.Internal.IO.Packaging.PackagingUtilities.SafeIsolatedStorageFileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, ReliableIsolatedStorageFileFolder folder)
   at MS.Internal.IO.Packaging.PackagingUtilities.CreateUserScopedIsolatedStorageFileStreamWithRandomName(Int32 retryCount, String& fileName)
   at MS.Internal.IO.Packaging.SparseMemoryStream.EnsureIsolatedStoreStream()
   at MS.Internal.IO.Packaging.SparseMemoryStream.SwitchModeIfNecessary()
   at MS.Internal.IO.Packaging.SparseMemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count)
   at MS.Internal.IO.Zip.ZipIOFileItemStream.Write(Byte[] buffer, Int32 offset, Int32 count)
   at MS.Internal.IO.Zip.ProgressiveCrcCalculatingStream.Write(Byte[] buffer, Int32 offset, Int32 count)
   at MS.Internal.IO.Zip.ZipIOModeEnforcingStream.Write(Byte[] buffer, Int32 offset Int32 count)

Update:

Additionally one can experience issue because to access IsolatedStorage your code must have all the necessary native platform operating system rights and if it doesn’t it will fail to create an IsolatedStorage stream.

The decision to make use of Isolated Storage here was not a very good and one another developer Eric White was kind enough to rewrite System.IO.Packaging to not use Isolated Storage and his rewrite will be part of COREFX.

Update 2

A hotfix for the .NET Framework 4.5, 4.5.1, and 4.5.2 on Windows 8.1 and Windows Server 2012 R2 was released addressing this issue. In my case this does not help as I am stuck with .NET 3.5 for the given applciation.

Other problem indicated by Microsoft that could occur with System.IO.Packaging related to this are as follows.

A deadlock may occur when you use large packages on separate threads. System.IO.Packaging uses IsolatedStorage for packages that are larger than 10 megabytes (MB). When two or more threads use large packages, a deadlock may occur, even if the packages are independent. The deadlock involves two threads. One is waiting in IsolatedStorageFile.Lock while the other is waiting in another method of the IsoloatedStorageFile class. This issue is fixed by adding synchronization to System.IO.Packaging to avoid the problem in IsolatedStorageFile. Exceptions may occur when you retrieve PackageProperties from packages that are opened on separate threads, even if the packages are independent. The most common call stacks that arise from this are as follows:

System.Xml.XmlException: Unrecognized root element in Core Properties part. Line 2, position 2.     at
MS.Internal.IO.Packaging.PartBasedPackageProperties.ParseCorePropertyPart(PackagePart part)     at
System.IO.Packaging.Package.get_PackageProperties()
System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.  Parameter name: id     at
MS.Internal.IO.Packaging.PartBasedPackageProperties.ParseCorePropertyPart(PackagePart part)     at
System.IO.Packaging.Package.get_PackageProperties()