Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a Simple C# Wrapper to clean up code

Tags:

c#

I have this code:

public void Contacts(string domainToBeTested, string[] browserList, string timeOut, int numberOfBrowsers)
    {
        verificationErrors = new StringBuilder();

        for (int i = 0; i < numberOfBrowsers; i++)
        {
            ISelenium selenium = new DefaultSelenium("LMTS10", 4444, browserList[i], domainToBeTested);

            try
            {
                selenium.Start();
                selenium.Open(domainToBeTested);

                selenium.Click("link=Email");
                Assert.IsTrue(selenium.IsElementPresent("//div[@id='tabs-2']/p/a/strong"));

                selenium.Click("link=Address");
                Assert.IsTrue(selenium.IsElementPresent("//div[@id='tabs-3']/p/strong"));

                selenium.Click("link=Telephone");
                Assert.IsTrue(selenium.IsElementPresent("//div[@id='tabs-1']/ul/li/strong"));
            }
            catch (AssertionException e)
            {
                verificationErrors.AppendLine(browserList[i] + " :: " + e.Message);
            }
            finally
            {
                selenium.Stop();
            }
        }
        Assert.AreEqual("", verificationErrors.ToString(), verificationErrors.ToString());
    }

My problem is i would like to make it so that i can use the code surrounding the 'try' many many times in the rest of the code. I think it has something to do with wrappers, but i can't get a simple answer for this from the web.

So in simple terms the only piece of this code which changes is the bit between the try {} the rest is standard code that i have currently used over 100 times and is turning out to be a pain to maintain.

Hope this is clear, many thanks.

like image 487
Tangopop Avatar asked Dec 28 '22 14:12

Tangopop


2 Answers

Two obvious and somewhat equivalent suggestions:

  • Use a delegate to represent the code within the try block (e.g. Action<ISelenium>)
  • Use an interface to represent the code within the try block

Change the main method to accept a parameter of the delegate (or interface) type and execute it in the try block:

public void Contacts(string domainToBeTested, string[] browserList, 
                     string timeOut, int numberOfBrowsers,
                     Action<ISelenium> test)
{
    verificationErrors = new StringBuilder();

    for (int i = 0; i < numberOfBrowsers; i++)
    {
        ISelenium selenium = new DefaultSelenium
            ("LMTS10", 4444, browserList[i], domainToBeTested);

        try
        {
            test(selenium);
        }
        catch (AssertionException e)
        {
            verificationErrors.AppendLine(browserList[i] + " :: " + e.Message);
        }
        finally
        {
            selenium.Stop();
        }
    }
    Assert.AreEqual("", verificationErrors.ToString(),
                    verificationErrors.ToString());
}

Either way, you're separating the bit that changes from the bit that doesn't. I'd probably go with the delegate form, especially if you're using C# 3. You can then either put the code within a method and use a method group conversion, or use a lambda expression for small blocks.

like image 196
Jon Skeet Avatar answered Jan 17 '23 21:01

Jon Skeet


You can use delegates to achieve it:

public void Contacts(string domainToBeTested, string[] browserList, string timeOut, int numberOfBrowsers, Action<ISelenium> callback)
{
    verificationErrors = new StringBuilder();

    for (int i = 0; i < numberOfBrowsers; i++)
    {
        ISelenium selenium = new DefaultSelenium("LMTS10", 4444, browserList[i], domainToBeTested);

        try
        {
            // Here the delegate is called
            callback( selenium );
        }
        catch (AssertionException e)
        {
            verificationErrors.AppendLine(browserList[i] + " :: " + e.Message);
        }
        finally
        {
            selenium.Stop();
        }
    }
    Assert.AreEqual("", verificationErrors.ToString(), verificationErrors.ToString());
}

The call looks like:

var result = Contacts( /* your arguments */, ACallback );

And

private void ACallback( ISelenium selenium )
{
    selenium.Start();
    selenium.Open(domainToBeTested);

    selenium.Click("link=Email");
    Assert.IsTrue(selenium.IsElementPresent("//div[@id='tabs-2']/p/a/strong"));

    selenium.Click("link=Address");
    Assert.IsTrue(selenium.IsElementPresent("//div[@id='tabs-3']/p/strong"));

    selenium.Click("link=Telephone");
    Assert.IsTrue(selenium.IsElementPresent("//div[@id='tabs-1']/ul/li/strong"));
}

Note: you could pass more arguments than just ISelenium and of course return a result, too (by using Func<> instead of Action).

like image 42
tanascius Avatar answered Jan 17 '23 22:01

tanascius