This topic is really helpful for testers aiming to shift towards automated testing. Manual testers should grasp these concepts to communicate effectively with developers, create solid isolated tests, and comprehend how systems with multiple components function and get tested. Developers often write mocks and stubs, but QA can also plan tests considering these elements. Therefore, it's crucial to know what they are and understand the issues they help address. Let's dive in!
Explanation of mocks and stubs
Mocks and stubs help simulate certain behaviors or responses in the code so you can test it more effectively. They allow you to set expectations on how they should be called and what they should return. They are mostly used to isolate the being tested part and remove dependencies on other components.
By using mocks, you can create fake versions of these components to see how your code interacts with them. Mocks let you simulate specific behaviors or responses from these components so you can test different situations without involving the real components. For example, imagine a function that interacts with a database. You can mock the database object to return specific data when called, instead of querying the actual database. Mocks and stubs are often used to test systems dependent on third-party providers when you can't predict the third party's response, but need to test your system's behavior regardless.
Stubs are similar to mocks, but they are simpler. Stubs give canned responses to specific calls in your code. Imagine a function that calls an external API. You can stub the API response so that a tester doesn’t have to depend on the actual API during testing. For example, consider a function that calculates the total price of items in a shopping cart. Instead of getting the prices from a database or an external service, you can use mocks and stubs to simulate these components' behavior.
So why do testers and developers use these technologies?
Isolation. A main goal of mocks and stubs is to isolate the code during tests. Mocks and stubs help you focus on testing one part of the code at a time without interference from other parts. This isolation makes identifying and fixing bugs easier.
Controlled testing environment. With mocks, you can simulate different scenarios and behaviors of external components without their actual involvement. This lets you test how your code reacts to different situations, like a payment failure or an unsent email, without dealing with real payments or emails. Stubs, by contrast, give set responses to function calls, allowing you to test specific code paths.
For example, when testing an e-commerce website's checkout process, a tester wants to ensure the system handles payment failures well. By using a mock for the payment gateway, it is possible to test various payment responses like success, failure, or timeout. This lets a tester see how the code manages each scenario without having to process real payments.
Mocking for testers
One example of mocking is when you need to fake user actions on a login form. Instead of creating many user accounts to test, you can mock the authentication service to check the form's function. This not only saves time but also makes testing more effective.
Another case is when you need to test how the app deals with errors. By making mock error messages or wrong data inputs, you can make sure the app acts correctly and shows the right responses to users.
Here are a few more cases where this can be useful:
Testing an E-commerce site. For instance, you want to ensure the website handles payment failures well. Rather than handling real payments during tests (which could be complex and costly), you can create a mock payment system. This fake gateway imitates different payment outcomes, like success, failure, or delay. This lets you test how your code responds to each situation without real transactions.
Testing an email function. For example, the site sends confirmation emails when someone registers. You must check that the email function works right. Instead of sending emails every time you test, you can set up a mock email service. This service pretends to send emails and gives set responses, allowing you to check the email process without real emails.
Mocking tools overview
Mocking tools offer several benefits for testers:
Simplicity. Mocking tools make it easy to create and manage mock objects or functions. With just a few lines of code, you can set up mocks for external components or systems, allowing you to focus on testing the code.
Flexibility. These tools provide a wide range of features and options for customizing your mocks. You can simulate different responses, behaviors, or error conditions, and adjust your mocks to match specific testing scenarios and requirements.
Integration. Mocking tools integrate smoothly with popular testing frameworks and libraries, making them easy to include in your current testing workflow. Whether you use JUnit for Java, Pytest for Python, or Mocha for JavaScript, you'll find mocking tools that work well with your chosen testing setup.
The most popular mocking tools:
Mockito is widely used in Java development. Mockito lets you create mock objects and verify interactions with them.
// Create a mock object
List<String> mockList = Mockito.mock(List.class);
// Define behavior for the mock object
Mockito.when(mockList.get(0)).thenReturn("Hello");
// Verify interactions with the mock object
Mockito.verify(mockList).get(0);Sinon.js is another tool, commonly used in JavaScript testing. Sinon.js offers spies, stubs, and mocks for testing JavaScript code.
// Create a stub
var stub = sinon.stub();
stub.returns(42);
// Use the stub in testing
console.log(stub()); // Output: 42 Mockery is a flexible mocking library for Node.js. It's great for testing Node.js applications and provides powerful features for creating mocks on the fly, allowing you to mimic different dependencies and interactions in your tests.
// Import the module you want to mock
const myModule = require('./myModule');
// Import Mockery
const mockery = require('mockery');
// Enable mocking with Mockery
mockery.enable();
// Create a mock for the module
const mockedModule = {
// Define mocked functions or properties
myFunction: jest.fn(),
myProperty: 'mockedValue'
};
// Register your mock with Mockery
mockery.registerMock('./myModule', mockedModule);
// Use the mocked module in your tests
describe('Testing myModule', () => {
it('should call myFunction with the right arguments', () => {
// Call the function that depends on myModule
myFunctionCaller();
// Check that the mocked function was called
expect(mockedModule.myFunction).toHaveBeenCalledWith('argument1', 'argument2');
});
it('should give back the mocked value for myProperty', () => {
// Get the value from the function that depends on myModule
const value = myPropertyGetter();
// The returned value should be the mocked one
expect(value).toBe('mockedValue');
});
});
// Turn off Mockery after tests
afterEach(() => {
mockery.disable();
});Best practices and tips
Here's a quick guide to get you started with mocking and stubs; just keep it between us ;-).
Identify parts of the code for testing. Before using mocks and stubs, pinpoint the specific components or functions that require tests. This lets you concentrate your efforts and resources on the most important code areas.
Pick a known mocking framework. Plenty of mocking frameworks are available for various programming languages. Select one that many people use and that has good documentation to streamline and improve your testing process.
Make tests independent and isolated. Ensure each test you write with mocks and stubs stands on its own and doesn't depend on other tests. This approach makes it easier to find specific issues or bugs.
Use realistic data for tests. When you create mocks and stubs, opt for realistic data that truly reflects how the code operates in the real world. This way, you are more likely to spot edge cases or unforeseen results.
Try out different scenarios. Don't hesitate to test the code with a variety of scenarios. Simulate different inputs and outputs to check that the code manages various situations well.
Conclusion
Whether you decide to shift to automated testing is your choice. However, knowing the basics of mocking and stubs is essential, even for a manual tester; this way, you can explain why mocks are used in testing and succeed in the interview.