Yesterday I wrote about things testers can learn from developers. Today I’d like to cover the flipside of that picture: what developers can learn from testers. Yes, there’s a significant amount of knowledge that can flow the other way, too!
Developers can learn many things from testers that will help the team be more productive and ship better value to the customers. Unfortunately, devs will have to get past some stereotypes about testers. Too often testers get viewed as the angry, overly critical people who lose sight of important aspects of a project. Like focusing on shipping versus endless testing cycles…
Testers have a lot of great domain knowledge that developers may sometimes be lacking. Additionally, testers can help developers create systems that are easier to test, and better tested throughout the entire product lifecycle.
Let’s look at some specific area where developers can get some great help from testers.
Too often, little thought is given to testability at the user interface level. This creates a serious burden on testers who have to create convoluted find logic based on brittle or overly complex XPaths, or rely on fickle conditions such as inner text of target elements. Occasionally testers may mistakenly rely on dynamic IDs for locators.
ASP.NET webforms is a particularly egregious offender in this aspect due to its generation of ID values based on the control’s position in the overall control hierarchy. An example might be ctl00_SamplesLinks_ctl10_SamplesLink which is dependent on the position of at least two other controls in the hierarchy. This becomes a serious issue when trying to create flexible locators that won’t break when controls are added elsewhere in the DOM above the control.
Few developers understand the impacts of these design and development practices—because too often they simply pitch the UI over to testers and don’t get involved with writing UI automation tests!
Testers can educate developers to modify the user interface to make it more stable for functional tests. For example, the figure below shows a grid control populated with data. The ID of the grid by default would be ct100_MainContent—totally dependent on the grid never moving from its position in the MainContent div element.
In this example, however, the developer has appended “PeopleGrid” to the grid’s ID as shown in the .aspx page’s markup below, resulting in the more specific ID “ct100_MainContent_PeopleGrid” as shown above.
This means testers can now use a find expression for this grid using the “EndsWith” form.
These easy steps decouple the grid’s find logic from it’s location on the page and will dramatically increase the test’s flexibility when the page’s layout changes. (That’s a when, not an if!)
Yesterday we discussed code smells in software code. As developers become more involved in the whole team approach to software development, they will likely be part of creating test cases—automated, manual, or exploratory/session charters. The same principles of clean code apply to these test cases: it’s important to not conflate concerns, create complexity, ensure specificity and validity, etc.
Testers can provide critical feedback on these aspects of test case design.
It may be a sad stereotype, but too often developers focus on happy paths when designing systems or writing tests. They’ll miss critical boundary conditions, and sometimes don’t take the broader view on business use or infrastructure issues. Testers can help flesh out better designs for handling likely error conditions around inter-component communication, long-running asynchronous processes, and other architectural or design issues. It doesn’t matter that the tester doesn’t know how to code up a solution in these instances; it’s the tester’s domain knowledge and experience that are critical.
Testers can be a great help in pairing sessions whether developers are doing regular development or Test Driven Development as well. Take the following method as an example. It’s intended to compute the wages for hourly or salaried workers based on their rate and number of hours worked. Salaried workers get straight time no matter how many hours they work, and hourly workers get time and a half for anything over 40 hours. [NOTE: No, this is NOT production-ready code. This is sample code!]
public float ComputeWages(float hours, float rate, bool isHourlyWorker)
{
float wages = 0;
if (hours > 40)
{
var overTimeHours = hours - 40;
if (isHourlyWorker)
{
wages += (overTimeHours*1.5f)*rate;
}
else
{
wages += overTimeHours*rate;
}
hours -= overTimeHours;
}
wages += hours*rate;
return wages;
}
A developer might come up with a quick set of test cases similar to the following
Type Worker |
Hours |
Rate |
Expected |
Hourly |
40 |
5 |
200 |
Hourly |
41 |
5 |
207.50 |
Salary |
41 |
5 |
205 |
Salary |
40 |
5 |
200 |
Testers would quickly flesh this out with additional use cases for zero amounts in rate and hours, negative values for rate and hours, and would also likely ask domain-level questions like “How do we handle an hourly worker that switches to salary in the middle of a pay period?” or “What’s the maximum amount of hours an employee can work in a pay period?”
This sort of feedback, especially early in a project, can be a tremendous boon to a team as they work to deliver the highest value possible to their customers.
Testers can also provide helpful feedback on basic assumptions made about features’ value. Testers often act as customer advocates, and will likely have different insights into customer habits and desires. This can be something as simple as “Customers are very price sensitive and prefer cost as the default sort order, not alphabetic.”
More importantly, testers can help validate or disprove the basic value assumption of features before a single line of code is written. “No, we’ve never had any issues voiced from customers around confusing colors on the test list screen. What we do know is they want better sorting and searching features.”
This sort of collaboration can help head off wasted time creating features, and help the team focus on much more valuable, productive work.