Exiting Loops Using Timeouts

Problem
On certain occasions, a test’s execution should only continue after a certain event. You’re using a looping construct to check for a condition, and you want to know what to do when it has been met.

Solution
Use timeouts to avoid infinite loops.

Comments
You may want to implement global timeouts in your project to reduce maintenance.

Example

// Method that checks the existence of a file.
bool FileExists() {
    ...
}

// Decrease timeout by 1 and wait for a second with each iteration.
// After 10 seconds, break out of the loop.
var maxWaitTime = 10;
while (!FileExists()) {
    if (maxWaitTime == 0) {
        break;
    }
    maxWaitTime--;
    Thread.Sleep(1000);
}

Sleeps and Pauses

Problem
Your test automation isn’t synchronizing well with the application under test (AUT). You need a way for your script to wait until the application is ready for the next action. Should you implement sleeps or pauses in your tests to overcome the problem? Thread.Sleep(), anyone?

Solution
As a general rule, you should not insert pauses or sleeps into your automation code. The best solution is to write a custom routine or leverage an existing library (e.g. Selenium WebDriver) to wait on a property of a UI element.

Comments
Sprinkling hard-coded sleeps in automation code isn’t desirable, because scripts will wait for a specified amount of time regardless of the application’s speed. And, as a result, they will take longer to execute.

Example

// Wrong. Note the sleep that waits 5 seconds for the page to refresh.
browser.FindElement(By.Id("submitButton")).Click();
System.Threading.Thread.Sleep(5000);
Assert.That(browser.FindElement(By.TagName("body")).Text.Contains("Order No:"));

// Correct. Explicitly wait for an element before proceeding.
browser.FindElement(By.Id("submitButton")).Click();
WebDriverWait wait = new WebDriverWait(browser, TimeSpan.FromSeconds(5));
wait.Until(brw => brw.FindElement(By.Id("orderNo")));
Assert.That(browser.FindElement(By.TagName("body")).Text.Contains("Order No:"));

Record & Playback Automation

Problem
You want to know if it’s okay to use record and playback automation in real-world projects.

Solution
Avoid using record and playback to generate test automation code. Instead, manually develop an automation framework to support the tests you write.

Comments
In some scenarios, you may want to use a tool’s record feature to prototype a test or inspect how the tool is identifying UI elements.

Using the Obsolete Attribute

Problem
You have deprecated types or members, and you don’t want clients using them anymore. What should you do?

Solution
First, start by marking deprecated types and members with the Obsolete attribute. Do this in the first version released with the deprecated types. In subsequent versions, use the true argument of the Obsolete attribute to cause compile-time errors. This should force users to remove any reference to the member.

Comments
Use the Obsolete attribute’s Message property to specify what to use in place of the deprecated code. Also, don’t remove a type or member without marking it obsolete in at least one version of your library.

Example

// This usage causes a compilation warning.
[Obsolete("Use WaitForElement instead")]
void WaitForItem() {
    ...
}

// This usage causes a compilation error.
[Obsolete("Use WaitForElement instead", true)]
void WaitForItem() {
    ...
}

Serializable Attribute

Problem
You’re interested in knowing how to apply the Serializable attribute.

Solution
As a general rule, apply the Serializable attribute to all nonsealed classes. Yet, mark all non-serializable fields with the NonSerialized attribute.

Comments
This practice ensures that instances of a class, and all types that inherit from it, can be passed as arguments to remote methods.

The Conditional Attribute

Problem
You want to exclude a method and any statements that call it from a particular version of your application. How should you do it?

Solution
Prefer the Conditional attribute instead of the #if directive to exclude methods and all the statements that call them.

Comments
The Conditional attribute can abandon all statements that call a method, but it won’t discard the method definition itself. However, you can invoke the method via reflection.

Example

// This is incorrect.
#if BETAVERSION
    ShowSplashScreen();
#endif

void ShowSplashScreen() {
    ...
}

// This is correct. No need for an #if directive.
ShowSplashScreen();

[Conditional("BETAVERSION")]
void ShowSplashScreen() {
    ...
}

Rules for Success

Question
What are your top five rules for success?

Answer
1. Become self-reliant.
2. Be aggressive, attack, and operate on the offensive.
3. Cultivate grit and perseverance.
4. Develop into a person of value.
5. Never stop being a student.

Comments
In my opinion, the most important indicator of success in life is self-reliance. I’m with Robert Greene on this one. In life, the only constant is change. Depending on others, a job, a lifestyle, or anything for that matter, is just not reliable. As sad as it may be, you can only depend on yourself. So, I urge you to strive for bad-ass confidence. The next important value that I believe leads to success is aggression. No, I don’t mean being aggressive or belligerent to others. What I mean is it’s not enough to stand idly by waiting for the things you want. You need to attack and go get them. It’s better to let it all hang out than to be timid. What do you have to lose? In other words, don’t let things happen to you; instead, make them happen. Thank you, Dan Gable! Angela Duckworth’s noteworthy research revealed that grit and perseverance, in the long run, beat out talent. As a programmer and technologist, I personally take great comfort in this research. In general, however, you will constantly be challenged in life. Accept this fact and don’t give up easily. Simply put one foot in front of the other, take action, and grind. One of my favorite programmers, Sandi Metz, gave a great presentation on this. Albert Einstein said it best. “Try not to become a person of success but rather a person of value.” Strive to be useful at work and in your day-to-day life. Provide value, and the rewards will be aplenty. Finally, never stop learning. In order to be successful, you must have a basic understanding of what seems to be a limitless amount of topics. Continue to learn about your profession, but also learn about other important facets of daily life. For example, how a car works, how to prepare and file taxes, how to invest, and how to maintain your home. The list goes on.

The this Keyword

Question
What’s the best way to use the this keyword in C#?

Answer
Avoid using this to reference a field or property unless it makes the code clearer.

Comment
There is an exception, of course. Using this is okay in a method or constructor that contains a parameter or local variable whose name resembles a class-level field or property.

Example

class Car {
    // In a real-world app, these would be properties.
    public string Make;
    public string Model;

    public Car(string make, string model) {
        this.Make = make;
        this.Model = model;
    }
}

Non-CLS-Compliant Types in C#

Question
How do I handle public members that work with non-CLS (Common Language Specification) object types?

Answer
You want to avoid public methods or properties that take or return types that aren’t CLS-compliant. For example, unsigned integers. However, if you can’t avoid these members, mark them with the CLSCompliant(false) attribute.

Comments
The compiler only honors the CLSCompliant attribute for public members in public types. Additionally, a type or member can’t be marked as CLS-compliant unless the assembly is also attributed as CLSCompliant(true).

Example

public class SimpleClass {
    [CLSCompliant(false)]
    public void DoWork(uint someNumber) {
        ...
    }
}