Search code examples
c#methodscustom-attributesmicrosoft-test-manager

Use custom attribute to skip body method


I have the following function:

public void Test(string testString)
{
     //Do Stuff
}

At some points in my code, I have to repeatedly check if the parameter is empty string/null/whitespace to skip the body method. The usual ways I've done this till now, are the following:

public void Test(string testString)
{
     if(!string.IsNullOrWhiteSpace(testString))
     {
         //Do Stuff only if string has text in it.
     }
}

Or

public void Test(string testString)
{
     if(string.IsNullOrWhiteSpace(testString)) { return; }
     //Do Stuff only if string has text in it.
}

Is there a way to create a custom attribute that checks if the parameter of the function is empty etc, to skip the method? I've had some experiece (basic stuff), with custom attributes, but I can't figure out a way to make the attribute skip the method body.

The ideal end product of the implementation would be the following:

[SkipIfEmptyParameter]
public void Test(string testString)
{
     //Do Stuff only if string has text in it.
}

Of course, any suggestion is welcome that helps minimize the recurring code if the attribute implementation is not possible.

Edit: Example of the problem I want to solve.

I have the following methods. I get from Microsoft Test Manager, some parameters that our test scenario are expecting (what the values should be). There is a SharedStep implementation that asserts the user's info:

public void AssertUser(UserDTO expectedUserInfo)
{
    VerifyUserName(expectedUserInfo.name);
    VerifyUserSurname(expectedUserInfo.surname);
    VerifyUserAge(expectedUserInfo.age);
    VerifyUserHeight(expectedUserInfo.height);
}

private void VerifyUserName(string name)
{
     //If the string parameter is empty, means the MTM scenario does not
     //want to validate the user's name at this point, so skip the
     //verification below.
     if(string.IsNullOrWhiteSpace(testString)) { return; }

     //Do Stuff only if string has text in it.
}

private void VerifyUserSurname(string surname)
{
     //If the string parameter is empty, means the MTM scenario does not
     //want to validate the user's surname at this point, so skip the
     //verification below.
     if(string.IsNullOrWhiteSpace(testString)) { return; }
     //Do Stuff only if string has text in it.
}

private void VerifyUserAge(string age)
{
     //If the string parameter is empty, means the MTM scenario does not
     //want to validate the user's age at this point, so skip the
     //verification below.
     if(string.IsNullOrWhiteSpace(testString)) { return; }
     //Do Stuff only if string has text in it.
}

private void VerifyUserHeight(string height)
{
     //If the string parameter is empty, means the MTM scenario does not
     //want to validate the user's height at this point, so skip the
     //verification below.
     if(string.IsNullOrWhiteSpace(testString)) { return; }
     //Do Stuff only if string has text in it.
}

The "Do Stuff" contain Selenium implementation that handle WebElements and might be time consuming, so if we don't want to validate that specific value, we just skip the whole method.

Now, when creating the scenarios over to Microsoft Test Manager, the shared steps allows the tester to decide what elements of the page will be validated. If some of the parameters are empty, then the code just skips the blocks and goes to w/e validation the user wants (still, the implementation is for every info the user has, but we just assign value to each parameter we want to test, and every parameter that does not have a value, just gets it's method body skipped).

The problem is, if I want to change the condition of skipping the method, I will have to go to each method and manually change the IF statement. Hence why I though it might be a good idea to have an attribute for every method that validates information.

P.S. I'm talking about hundreds of methods that have the IF implementation at the start.


Solution

  • The way you are doing it is actually pretty good. But as Evk pointed out in the comments: You should extract the "skip checking" into a separate method, especially if the check is always the same and needs to be changed globally. Using an attribute would solve the problem, but is a little complicated to use.

    Instead, take a look at the code below. Looks pretty clear, doesn't it? Don't use too many comments (and don't copy-paste them into every method, that is of no use). This way, you have the same benefits as if you would use a custom attribute but without the ugliness of using reflection.

    public void AssertUser(UserDTO expectedUserInfo)
    {
        VerifyUserName(expectedUserInfo.name);
        VerifyUserSurname(expectedUserInfo.surname);
        VerifyUserAge(expectedUserInfo.age);
        VerifyUserHeight(expectedUserInfo.height);
    }
    
    private void VerifyUserName(string name)
    {
        if (ShouldSkipValidation(name)) return;
        // code here...
    }
    
    private void VerifyUserSurname(string surname)
    {
        if (ShouldSkipValidation(surname)) return;
        // code here...
    }
    
    private void VerifyUserAge(string age)
    {
        if (ShouldSkipValidation(age)) return;
        // code here...
    }
    
    private void VerifyUserHeight(string height)
    {
        if (ShouldSkipValidation(height)) return;
        // code here...
    }
    
    // The MTM scenario does not want to validate values that satisfy the check below
    private bool ShouldSkipValidation(string value)
    {
        return string.IsNullOrWhiteSpace(value) || value == "<>";
    }