How to Get Started with Software Testing

You’ve forgotten to add frontend validation to number fields, and now people are getting an error when they enter text into those fields. However, this is an issue that’s easily preventable—by implementing a proper test that checks for edge cases, but how do get started with software testing?

Avoiding bugs in production is just one advantage of testing, it also helps you be more confident about your applications, opens up the potential for a full CI/CD pipeline, and much more.

In this post, we’ll introduce you to software testing, as well as provide pointers on how to move from beginner to advanced.

What is Software Testing?

There are many ways to implement software testing—from unit tests, to integration tests and performance tests—all of which will be covered later in this post.

At a high level though, testing is the principle of running through specific scenarios to ensure that your application works properly. This can either be done manually by a QA tester, who will click through an application in a specific order, or—as is becoming much more common—tests can be automated. This can be done by coding tests directly into your application, which can then be run locally by a developer, for example by running a npm test if you’re using node.

Alternatively, you can use third-party tools that automatically create tests for you, based on what’s happening in your production environment. In any case, the point of the tests is to test specific user behavior and make sure your application responds as expected.

It should be mentioned that while there’s a general consensus on what types of tests exist in software testing, you will find some folk argue about exactly what constitutes performance testing, or indeed other forms of testing.

The best way of getting started in software testing is to make sure you have a general overview of what’s possible in the world of testing, which Martin Fowler has a great resource on.

How to Get Started With Software Testing

There may be discussion about some types of testing, but there are certain areas where most engineers agree. When getting started, it pays to be familiar with:

  • Unit tests,
  • Integration tests,
  • End-to-end tests.

These three test types lay the principles for most other forms of testing. So, if you’ve understood and worked with these types of tests, you should be able to participate in any discussion around software testing.

When you’re just starting out, however, here’s the best way to go about learning.

Start with Simple Unit Tests

Unit tests are by far the simplest form of software testing and is likely where you should get started with software testing. As the name implies, this is where you test a single unit of your application.

Going back to the example mentioned in the introduction, let’s say you’ve implemented a new form on your website, and one of the fields only accepts numbers. In that case, you want to show an error if anyone inputs text.

After you’ve implemented the validation, you also want to make sure that it works as expected. You can do this by manually testing different inputs like “xyz”, “123”, “xa1”, etc.

However, you want to be sure that two months from now—when something about the form has changed—the validation still works. Yes, you can manually test the inputs again, but that’s far from optimal. Not only is there a chance you will forget, but there are also more valuable things for you, as a developer, to spend your time on.

Instead, you code a simple test that calls your validaton function with different inputs:

Note that the examples shown from here on have been simplified in order to focus on learning the principles of testing. Examples may need modifications to work in production.

function testFormValidation() {
    const inputs = ["xyz", "123", "xa1"];
    const expectedResult = [false, true, false]
    inputs.forEach(x => {
        assertEquals(validateInput(x), expectedResult[inputs.indexOf(x)]);
    })
}

In the above example, the assertEquals function will come from your testing framework, and will verify that the two arguments match each other. In this case, it’s assumed that the validateInput() function returns true if the validation passes.

You might also notice that the example doesn’t just test “123” to ensure that the validation passes. You want to make certain that you’re also including edge cases.

Unit tests aren’t always about testing self-contained functions. Imagine that the validateInput function calls a getRegex function to get the validation requirements. In a unit test you only want to ensure that the validateInput function works, and remove any reliance on other functions like getRegex.

To accomplish this, developers can use mocks to, well, mock the behavior of other functions.

function testFormValidation() {
    mock('getRegex', () => {
        return '^[0-9]*$';
    })

    const inputs = ["xyz", "123", "xa1"];
    const expectedResult = [false, true, false]
    inputs.forEach(x => {
        assertEquals(validateInput(x), expectedResult[inputs.indexOf(x)]);
    })
}

This ensures that any changes to the getRegex function won’t make the testing of validateInput fail.

Perform Integration Tests

Once you’ve tested the individual parts of your application, it’s time to make sure that they all work together to form a robust, cohesive application. This is where integration testing comes into play.

In the previous section you saw how you can use mocks to ensure that only a specific part of your application is being tested. In integration testing, the whole point is that rather than using any mocks, instead you’re allowing the different parts of your application to work together.

So, when you’re performing integration tests, the previous example would once again look like this:

function testFormValidation() {
    const inputs = ["xyz", "123", "xa1"];
    const expectedResult = [false, true, false]
    inputs.forEach(x => {
        assertEquals(validateInput(x), expectedResult[inputs.indexOf(x)]);
    })
}

It’s important to note that this is a very simplified way of presenting integration tests. Check out this post to see some more advanced examples.

Learn about End-to-End Testing

While integration tests are meant to ensure that all the different parts of a given application work as intended, end-to-end tests are meant to ensure that your entire infrastructure works as expected.

So far, we’ve used the example of testing frontend validation. But in the real world, you also want to make sure that the input still works once it’s been sent to the backend. This type of testing is quite a bit more advanced than the previous two examples, as it requires you to be running multiple services simultaneously.

It’s also not uncommon to see very few companies that have implemented end-to-end testing, because of the infrastructure challenges it brings.

To get a deeper dive into what end-to-end-testing is and how to implement it, check out this blog post.

Advancing into Advanced Testing Types

Once you’re done working on your shiny new feature, you now have a baseline knowledge of how you can make sure it’s properly tested, and thereby make certain that users won’t experience bugs.

To get started with software testing you’ve been introduced to the three main types of testing; unit testing, integration testing, and end-to-end testing. However, that’s just the beginning. From here, you’ll be able to start looking into more advanced testing methodologies like performance testing and load testing.

Once you’re ready for a deeper dive, take a look at how you can implement load testing in Kubernetes.

Get started with Traffic Replay today

Free for 14 days. No credit card required.

    About The Author