Testing without a user interface may seem challenging but there are ways to help ease the process. Most agile projects I have worked on go something like this: Developers work on new code changes for two-thirds of a sprint. Halfway through the second week, they give the test team a new build to work with. The testers work hard and discover some important bugs, but eventually they run out of time.
Let’s unpack that. There are a couple of problems that cause the test team to not be able to examine the product until it is very late in the sprint. The developers aren’t breaking stories into small, deliverable pieces of code, so deliveries come late and unpredictably. And the testers aren’t able to be effective earlier in the process, either because of organizational design or a skills gap.
Teaching how to test without a user interface will solve some of these problems.
1 – Feature Reviews
I was recently working on a change to restyle the page where a user can change their password. When a user logs into our software for the first time or they have their password reset, the first place they land is a page instructing them to change their password. The new page was going to be updated to use the latest product design standards, as well as include some usability features around the password rules.
The developers did what was in the card: update the page styling and add highlights when a password criterion, such as special characters, is met. I started looking at how the new styling was supposed to work and noticed a combination of missing elements and incorrect scope. Having to discover some requirements and fix others made this change span an entire week when it was originally supposed to take only a day or two.
Our JIRA card was created without a developer or tester around to talk through the idea. If I had the opportunity to test this change again, I’d start when the product manager is creating the card.
While the product manager is describing the change, the developer can think through the problem from an implementations point of view. How does a user currently log in? What information do we have about a person before and after they log in? What parts of our code handle this activity, and how do the different pieces integrate?
Meanwhile, the tester will think about the problem from the perspective of a person who will be using the change. What happens if I enter my old password wrong on the password change screen? What happens if my new password doesn’t meet security requirements?
After this line of questions, ideally we will have discovered missing requirements and corrected some things that don’t need to be there.
Testing a software feature when it is only an idea is a skill, just like testing a change in a piece of live software. Missing or implicit requirements are the most common things I discover in a feature review. For example, I might ask what the upper limit on the number of elements in a configurable drop list should be, or how many characters each element should be, or if a blank element is acceptable. These are the types of questions other roles forget to ask when initially looking at a new software change. The combination of skilled testers and developers working at this level can help prevent development time jumping from a day to a week.
2 – Test Coaching
The role I am working in today involves being embedded on small development teams. Each team has two testers and one developer. The three of us work together on a feature from start to delivery.
This begins with a meeting to get everyone up to date on the request, a strategy called the Three Amigos. After the meeting, the three of us begin working on the feature change. The developers write a combination of production code and test code, and I begin working on reviewing our UI automation around the area the developers are touching. This is a combination of building or refactoring page objects and writing Cucumber and Gherkin files. Sometimes I update our behavior-driven development (BDD) scenarios, sometimes I need to build a new one or two, and sometimes I get the pleasure of deleting some test code because a scenario is covered more appropriately at a different level.
The work isn’t entirely asynchronous like that, though; the majority of the time, we work as a group on a change. One developer is at the keyboard writing code, or “driving.” The other helps by asking questions about the implementation that should result in code that is more readable or more stable. My role as a test specialist in the group is to guide us toward building the right test at the right level in the product.
We use a combination of Cucumber tests that run against the user interface, service-level tests that run against a RESTful API, Jasmine to test JavaScript code, and RSpec to test closer to the unit level. For example, while working in the Cucumber tests, I might notice that we have several tests making assertions about what happens when we enter different types of data. In our case, it might be more appropriate to test this against the API by creating a CSV file with each piece of data to loop through, then checking the JSON response after each call. (It is difficult to define what “more appropriate” means, but in this case I would make this choice because I can get the same test coverage much faster by using the API instead of the user interface.)
When we review those tests as a group, the developers might notice a test that they have already covered, or some missing coverage, and then we will talk about the right place to build those requirements—or if we even need to build them at all. After this, we will walk through the test coverage the developer pair wrote. I might ask questions, like “What happens if this field is null?” or “Where is this scenario tested?” or ask if we wouldn’t be better building a certain test at a different level in our test stack.
Test coaching is testing at a very granular level. The result is an optimized layering of tests that force developers to refactor their code while it is being written. Test coaching as a strategy also sometimes results in much better first-time builds. Instead of getting a testable build and discovering that you can’t log in or that there are a bunch of low-hanging-fruit-type bugs, you have to actually think and work hard to find a problem.
Join 34,000 subscribers and receive carefully researched and popular article on software testing and QA. Top resources on becoming a better tester, learning new tools and building a team.
3 – The API
Building software on top of a service layer is one of the more popular architectural styles today. That service layer might be a RESTful API, web services, or microservices. I see REST APIs and web services more than anything else. From a development perspective, using services allows someone to make a software change and reduce the risk that it might unexpectedly affect something else in the product, because each piece of the product is somewhat isolated. From a testing perspective, an API means I can approach testing well before a user interface is ready.
Building automation that can be run in Continuous Integration is one popular way to test an API, but you don’t necessarily need to do that. Let’s say your developers are making some changes to the login process. You want to make sure that password rules are still enforced when resetting a password, you want to know that a user is locked out after three failed login attempts, and you want to make sure that a password for an existing user can be reset. You could test this through a user interface, but the UI changes associated with the development work aren’t ready yet.
I could use a tool like Postman to test all of this. Alternately, for people who prefer a command-line interface, there is always cURL and HTTPie, and for the automators, there are libraries like Frisby.js and Airborne.
Let’s look at the user lockout example. My preference would be to make a small script with Airborne. I would make a call that posts to the login endpoint and loop through that call three times. On the third time, I would look at the response and make sure the locked flag is set to true. If I wanted to make this test reusable, I might add one more call after the main test to unlock that user so that the scenario wouldn’t be dirtied the next time I wanted to run the script.
The API allows you to test without a user interface, but it also facilitates getting through a lot of data or scenario testing very quickly. Scenarios that usually look like “enter text in first name, enter text in last name, click submit, check result” can be transformed into a few lines of code and a CSV file.
Being an Effective Tester
These three ideas span from not technical at all to where you will probably be better off if you are comfortable writing a few lines of test code. My hope is that you can pick one or two of these ideas to try on Monday and become more productive and effective at delivering quality information much earlier in the development cycle.
Remember, these aren’t replacements for the testing you normally do; they are supplements. Testing without a UI helps design better code and potentially helps to resolve problems that would be found later, when a full user interface is ready.
How do you approach testing without a UI? Follow us on Linkedin for weekly articles and software testing updates.