Users want good, reliable experiences when using apps and websites. They want to avoid buggy styling, incorrect data, or 404 missing page errors appearing when they try to check their bank account or order an item online. Software engineers cannot fix issues having to do with server outages or personal device issues. They can ensure their software is resilient enough to handle user interaction and data issues. This is where testing comes into play with software engineering. Testing software is writing automated or manual methods to check that software works under expected and adverse conditions.
Table of Contents
Why do Software Engineers Need to Test?
There are many benefits to testing software. The most apparent one is to ensure a good user experience for your customers. Broken code breaks trust in the ability and security of an application. It is a poor user experience if an image size flickers on your mobile device because the styling needs to be more responsive. This behavior will annoy users but should not cause any lasting harm. However, if a planned bank payment fails due to incorrect API configurations, you may cause the user to miss payments. This may incur late fees for them and lower their credit score. This will cause a loss of trust and users.
Speed Up Your Development
Testing is sometimes seen as an unnecessary step in software development. It takes more time to write test code after writing the original code, and the test code can sometimes often be 2-3 times longer than the code it is testing. It also adds more work past the development phase when development is separated from testing.
This testing has an upfront cost before shipping code but helps speed up development in several ways. First, by writing tests for your code, you prevent bugs from being shipped to production. This stops bugs from being found by users, reported to project managers, turned into tickets, and reassigned to a developer. The time for testing is much less than the time for this reporting and fixing process.
Testing also reduces the amount of spaghetti code, or non-concise and unclear code written. When developers write testable code, they produce cleaner code that allows tests to call and check the output of each method.
Finally, they make the deployment process a lot smoother. Whether you or other team members write code, your team will probably use a testing suite to ensure all tests pass for new features being deployed to production. By writing test code, you can make the deployment process smoother as you will be assured your changes will not cause issues with new or existing features.
Create Documentation for Your Software
Writing software tests allows us to automatically check that your software works and also serves as documentation. Each group of tests, and individual tests, tells the story of an expected action in your software. This story is the input of an action a user might perform, the method that will handle this action, and what you expect for the output.
These tests are great context for other team members who perform reviews or even help onboard new members on a project without them having to dig through source code. When tests are written and organized correctly, they should allow other developers to quickly determine what functionalities a software offers and the different expected user interactions that may happen.
What is Unit Testing?
Unit tests are the atomic parts of a testing suite. It is a way to test the smallest piece of code that can logically be isolated for a software system. We must examine two parts of this definition. The first is the smallest piece. Unit tests do not act on whether a web page renders, or a server is configured correctly. They only focus on the minor parts of these items.
When building a word processor, a unit test would not test if the whole text were formatted correctly. Instead, you may have a test to check that letters are capitalized when followed by specific punctuation or that an error is shown if parentheses are opened without being closed. These test small, specific functionalities rather than how these features come together.
The other part of unit tests is that they are isolated. Again, they should have a narrow focus on what they are testing. We want to see how they work and ensure that their functionality is tested and works even if the code around the test subject changes. When writing unit tests, we want to isolate the functionality and the test to ensure that the tests pass as long as the specific code works.
How do Integration Tests Work?
While unit tests are isolated and specific, integration tests focus on how different methods and features come together. They are used to verify that modules and components work together correctly.
Integration tests are much harder to write and maintain than unit tests because they test interfaces instead of methods. We see integration tests when combining work from two teams or integrating internal features with external services or modules. This could be integrating a product team’s UI into a record team’s database or building product features with an external API or data warehouse.
These tests are critical to write and maintain because working with other teams’ code makes your integrations more likely to fail. It is easier to keep code functional when working with a single team. As other teams change the code your features rely on, there are many opportunities for the interfaces to change and break.
Stubbing and Mocking Actions and Calls
Sometimes we need to test actions downstream from a user interaction but do not want to set up complete integration tests. This is where we introduce the ideas of stubbing and mocking. Stubbing and mocking are often confused for being similar but are separate testing items.
Stubbing involves creating placeholder data to act on or return specific data for an action. We may stub the result for our record if our server performs several steps on the record before returning the transformed data. Thus, when a user calls the transform method, we return the stubbed value instead of executing the transform methods on the original data. We would use this when we have already unit tested all operations performed on the object and want the result without testing the steps.
Mocking is similar, but instead of mimicking operations on data, we mimic calls to an API or service. Testing calls to 3rd party APIs, and services can introduce several issues to your tests. These calls can be unreliable as your test code may be sufficient but fail due to server outages or network congestion. Along with being flaky, calls to external services make your tests slow. Each test may require seconds to execute, which adds up when you have large projects with thousands of individual test cases to run.
When you mock a call, you make the call one time and save the HTTP response in a file. There are many popular gems and packages to do this. Ruby’s VCR gem is a popular package for generating YAML HTTP response test files. After you run the test once to get a response, the test will use the mocked call file to mimic and test the response. This eliminates the need to make external calls which speeds up tests and ensures the reliability of test suites.
Test Driven Design (TDD)
Test Driven Development (TDD) is a testing approach that encourages software engineers to write tests for code before developing the code itself. This method is similar to writing an outline for a paper or report in that you plan, revise, and finalize the structure and expectations for each section of code before writing a line of content.
TDD helps with several problems: hard-to-test code, spaghetti code, and missing edge cases.
Because you approach the code by writing tests, you ensure that you will be able to test the code. Each set of test cases will relate to a single method you are writing. First, write the tests you want your code to pass, then write the code to fulfill your tests.
This solves the issue of missed edge cases as you are forced to think about all inputs your method could expect from users and write individual tests for each situation. Writing the code solution will give you real-time feedback on whether you covered the edge cases, as your tests will either pass or fail.
The final issue TDD addresses is spaghetti code. This is a software engineering term for code that works but is hard to read, adjust or expand. We often see spaghetti code when developers start coding before fully understanding their problem. TDD forces developers to think before typing, leading to more concise code solutions.
Want to Learn to Write and Test Code?
Testing is only one part of the software development lifecycle. You must understand how code works in a system before you can test your code. If you want to become a full-time software developer, start a 5-month Software Engineering Bootcamp.In this bootcamp, students learn how to develop front-end and back-end programs, test code, and manage complex releases!
Anjani is a technical as well as creative content writer at Thinkful, a Chegg service. She is an outgoing person, and you will find her near books, arts and explore the miraculous world of technology. Connect with her on LinkedIn or Twitter.