Thursday, March 24, 2011

How to simulate network failure for test purposes (in C#)?

I'm building what could be called the DAL for a new app. Unfortunately, network connectivity to the database is a real problem.

I'd like to be able to temporarily block network access within the scope of my test so that I can ensure my DAL behaves as expected under those circumstances.

UPDATE: There are many manual ways to disable the network, but it sure would be nice if I could enable/disable within the test itself.

From stackoverflow
  • Try blocking the connection with a firewall midway through the session maybe?

    I like the wrapper idea as well, but thats kind of abstracting the problem and you prolly might not get exact real world behavior. Also, inserting the wrapper layer and then removing it may be more trouble than its worth.

    Edit: Run a script that turns the Network adapter on/off randomly or at set intervals?

  • Write a wrapper to the network class connectivity class you're using (e.g. WebClient) with an on-off switch :)

    Either that, or block your application in the firewall.

  • Look for a WAN simulator that will allow you to restrict bandwidth (and cut it off completely) I always find it interesting to see how the user experience changes when my apps are run in a bandwidth restricted environment. Look here for some information.

  • There is a tool you can use for simulating High Latency and Low Bandwidth in Testing of Database Applications as explained in this blog entry.

  • If you are trying a complete network outage for your application unplugging the network cable will work. Sometimes you might have a data access layer with multiple data sources (on different machines) in which case you can simulate an exception in your tests with a Mock Framework like Rhino Mocks. Here is some pseudo-code that you may have in your test

    void TestUserDBFailure()
    {
        // ***** THIS IS PSEUDO-CODE *******
        //setting up the stage - retrieval of the user info create an exception
        Expect.Call(_userRepository.GetUser(null))
           .IgnoreArguments()
           .Return(new Exception());
    
        // Call that uses the getuser function, see how it reacts
        User selectedUser = _dataLoader.GetUserData("testuser", "password");        
    }
    
  • Use mock objects to create configurable, destructible versions of the real thing--in this case, the database.

  • Probably not helpful for simulating "real" network issues, but you could just point your DB connection string to a non-existent machine while within the scope of your test.

    Larsenal : I agree that a simple enable/disable doesn't get you very far in dealing with "real" network issues, but it's a starting point for testing what happens to the app when connectivity is down.
  • For the time being, I'm just "disabling" the network by setting a bogus static IP as follows:

    using System.Management;
    
    class NetworkController
    {
    
        public static void Disable()
        {
            SetIP("192.168.0.4", "255.255.255.0");
        }
    
        public static void Enable()
        {
            SetDHCP();
        }
    
    
        private static void SetIP(string ip_address, string subnet_mask)
        {
            ManagementClass objMC = new ManagementClass("Win32_NetworkAdapterConfiguration");
            ManagementObjectCollection objMOC = objMC.GetInstances();
    
            foreach (ManagementObject objMO in objMOC) {
                if ((bool)objMO("IPEnabled")) {
                    try {
                        ManagementBaseObject setIP = default(ManagementBaseObject);
                        ManagementBaseObject newIP = objMO.GetMethodParameters("EnableStatic");
    
                        newIP("IPAddress") = new string[] { ip_address };
                        newIP("SubnetMask") = new string[] { subnet_mask };
    
                        setIP = objMO.InvokeMethod("EnableStatic", newIP, null);
                    }
                    catch (Exception generatedExceptionName) {
                        throw;
                    }
                }
    
    
            }
        }
    
        private static void SetDHCP()
        {
            ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
            ManagementObjectCollection moc = mc.GetInstances();
    
            foreach (ManagementObject mo in moc) {
                // Make sure this is a IP enabled device. Not something like memory card or VM Ware
                if ((bool)mo("IPEnabled")) {
                    ManagementBaseObject newDNS = mo.GetMethodParameters("SetDNSServerSearchOrder");
                    newDNS("DNSServerSearchOrder") = null;
                    ManagementBaseObject enableDHCP = mo.InvokeMethod("EnableDHCP", null, null);
                    ManagementBaseObject setDNS = mo.InvokeMethod("SetDNSServerSearchOrder", newDNS, null);
                }
            }
        }
    }
    
  • Depends on what particular network problem you wish to simulate. For most folks, it's as simple as "server unreachable", in which case you'd just try to connect to a non existent server. Be careful, though, because you want something that is routable but does not answer. Trying to connect to dkjdsjk.com will fail immediately (DNS lookup), but trying to connect to www.google.com:1433 will (probably) time out due to a firewall - which is how your app will behave when your DB server is down.

0 comments:

Post a Comment