Test cases help validate the correctness of your solution by ensuring it works for all possible scenarios, not just typical cases. They demonstrate your critical thinking and thorough understanding of the problem.
During the technical round of an interview, the interviewer expects the candidate to come up with a solution that is complete, runs perfectly, and includes all of the necessary checks to pass the problem’s constraints. Although presenting a solution and choosing the correct coding pattern is a bonus, writing a well-designed solution that passes all test cases can set you apart!
Testing your solution on various test cases showcases your understanding of the problem and ability to think critically about various scenarios. In this blog, we’ll cover how to create effective test cases to impress interviewers and validate your solutions. Here’s a quick breakdown of the blog structure:
What does an interviewer expect during a coding round interview?
Strategies for developing good test cases for your solution.
What are equivalence classes, and how are they beneficial in creating good test cases?
During the interview, what types of test cases are a must to test the correctness of your solution?
Practice with a sample problem and incrementally build test cases for that problem.
What common mistakes can be avoided during test case generation?
Some of you might say that you have written the solution the interviewer asked for, which might be correct in some cases. There’s nothing wrong in thinking this way, but although your interviewer is looking forward to a correct solution, they are also expecting you to write a solution that passes all of the validity checks necessary to finish the coding round.
Test cases are important to ensure that you understand what is expected of you and that you can think outside the box.
The first step is to understand the problem. When the interviewer presents a problem statement, they expect that you fully understand it and its constraints and that you write well-designed code. The key to achieving this is by communicating with the interviewer. Ask the interviewer if there’s any confusion regarding the problem.
Once you have written your solution, debug it on custom test cases. Ask about the constraints and ensure that you do not miss any important checks. Pay attention to input ranges, the data types given, output requirements, and any other specific constraints or conditions mentioned.
The interviewer always sets a few loopholes or tweaks to check a candidate’s critical thinking and analytical skills. Online coding platforms like LeetCode and Grokking the Coding Interview course at Educative use bulked-up boundary-level test cases to deeply evaluate how memory efficient a program is and how much time it takes to execute.
The first task that can help you create a baseline for good test cases is writing equivalence classes.
Equivalence classes categorize input data into groups where all elements behave similarly based on a specific property. This approach is used to minimize redundant testing by selecting representative values from each group to ensure comprehensive coverage.
The key idea behind equivalence classes is to divide the input data into different groups that are expected to be treated similarly by the system. By selecting one representative test case per class, you minimize the number of test cases while ensuring full coverage of different input behaviors. If one test case in an equivalence class finds a bug, other test cases in the same class are likely to find the same bug. Alternatively, if one test case works, the others are likely to work as well.
Effective test cases require an organized approach. Here are some tips that can help you write great equivalence classes:
Start by identifying the different input values for the problem. These values can include different ranges of the data and null value checks.
For example, if a function accepts an integer input, possible input values could be:
Positive integers
Negative integers
Zero
Group the inputs into equivalence classes based on the identified conditions. Each class should cover a set of inputs that are expected to be processed in the same way.
Using the previous example, the equivalence classes for an integer input might be:
Values above zero: Any positive number (e.g., , , )
Values below zero: Any negative number (e.g., , , )
Zero: The value
Choose one representative value from each equivalence class. This reduces the number of test cases while ensuring that each class is tested.
For our example, the representative values could be:
Positive integer:
Negative integer:
Zero:
In addition to representative values, consider boundary values within each equivalence class. Boundary values often reveal edge cases that might cause the system to behave unexpectedly.
For the integer input example, boundary values might include:
Values above zero: (smallest positive), (largest positive if using 32-bit integer)
Values below zero: (smallest negative), (largest negative if using 32-bit integer)
Zero: (already included)
Creating various types of test cases ensures comprehensive coverage of the solution’s behavior. Each type addresses different scenarios and potential issues. In this section of the blog, we’ll look at different types of test cases that you can check during your interview. For a better understanding, we’re going to debug each type of test case on the Combination Sum problem from the following course:
With thousands of potential questions to account for, preparing for the coding interview can feel like an impossible challenge. Yet with a strategic approach, coding interview prep doesn’t have to take more than a few weeks. Stop drilling endless sets of practice problems, and prepare more efficiently by learning coding interview patterns. This course teaches you the underlying patterns behind common coding interview questions. By learning these essential patterns, you will be able to unpack and answer any problem the right way — just by assessing the problem statement. This approach was created by FAANG hiring managers to help you prepare for the typical rounds of interviews at major tech companies like Apple, Google, Meta, Microsoft, and Amazon. Before long, you will have the skills you need to unlock even the most challenging questions, grok the coding interview, and level up your career with confidence. This course is also available in JavaScript, Python, Go, and C++ — with more coming soon!
Positive test cases ensure that the solution works as expected with valid and typical input data and verify that it produces the correct output for standard input values within the expected range.
Negative test cases check how the solution handles invalid or unexpected input data. These test cases help ensure that the solution gracefully handles errors, invalid inputs, or out-of-bound conditions without crashing or producing incorrect results.
Edge cases test the solution with extreme values or limits of the input data. These cases help identify potential issues that might arise when the input values are at their minimum or maximum limits, such as an empty array or the largest possible integer.
Performance test cases evaluate the efficiency and scalability of the solution by using large input data sets. These cases ensure that the solution can handle high loads and perform well within acceptable time and resource limits. Coding platforms such as Educative, LeetCode, HackerRank, etc., use a large number of test cases to validate the program’s performance.
Language-specific test cases consider unique behaviors or limitations of the programming language being used. These cases might test for issues like integer overflow, memory management, or specific exceptions relevant to the language.
Data type test cases ensure that the solution correctly handles different data types as input. These cases verify that the solution can manage various data types appropriately, such as integers, strings, and floating-point numbers, and correctly handles type-related errors.
Let’s look at the Combination Sum problem and see a step-by-step process of how we can create equivalence classes to come up with good test cases during an interview.
Given an array of distinct integers, nums
, and an integer, target
, return a list of all unique combinations of nums
where the chosen numbers sum up to the target
. The combinations can be returned in any order.
An integer from nums
can be chosen an unlimited number of times. Two combinations are unique if the frequency of at least one of the chosen integers is different.
The constraints are determined by the computational power of the execution platform and the requirements of the problem at hand. The following restrictions for the Combination Sum problem are also influenced by these factors.
Constraints:
nums.length
nums[i]
target
All integers of nums
are unique
What are constraints?
Constraints are rules or limits defined in a problem statement that specify the conditions to which the inputs and outputs must adhere. They provide boundaries within which the solution must operate. Constraints can include the input size, the range of values, and specific conditions the input data must satisfy.
Why do these constraints matter?
Array length (nums.length
Element values (nums[i]
Target value (target
Uniqueness of integers: This condition simplifies the problem since you don’t need to handle duplicate values in the input array.
There can be many equivalence classes for this problem, but during the interview, you won’t have enough time to test all the classes. What can you do in this case?
So far, we know what equivalence classes are and why they are important in developing good test cases during an interview. A few useful classes can be:
Normal range inputs
Class 1: Typical case with various possible combination sums.
Class 2: Typical case with no possible combination sums.
Boundary conditions
Class 3: Minimum length of nums
(
Class 4: Maximum length of nums
(
Class 5: Minimum target value (
Class 6: Maximum target value (
Edge cases
Class 7: Combination sums requiring all elements of nums
.
The above classes can be beneficial to use during your interview. Luckily, in this problem, the constraints tell us that the values for nums
are between
def combination_sum(nums, target):# Initialize dpdp = [[] for _ in range(target + 1)]dp[0].append([])# For each value from 1 to targetfor i in range(1, target + 1):# Iterate over numsfor j in range(len(nums)):if nums[j] <= i:# Check previous results from dpfor prev in dp[i - nums[j]]:temp = prev + [nums[j]]temp.sort()# If the new combination is not already in dpif temp not in dp[i]:dp[i].append(temp)# Return the combinationsreturn dp[target]# Driver codedef main():nums = [# Class 1: Typical Case with Various Combinations Possible[2, 3, 6, 7],# Class 2: Typical Case with No Combinations Possible[5, 6],# Class 3: Minimum Length of 'nums' (1 element)[2],# Class 4: Maximum Length of 'nums' (30 elements)[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],# Class 5: Minimum Target Value (1)[3, 5, 7],# Class 6: Maximum Target Value (40)[1, 2, 4],# Class 7: Combination Sums Requiring All Elements of 'nums'[2, 3, 5]]targets = [7, 4, 6, 30, 1, 40, 10]for i in range(len(nums)):print("Class ", i+1, ".", " nums: ", nums[i], sep="")print("\t target: ", targets[i], sep="")combinations = combination_sum(nums[i], targets[i])print("\nOutput: number of combinations: ", combinations, sep="")print("-" * 100)if __name__ == '__main__':main()
Lines 1–20: Includes the actual implementation of the algorithm used to find the combination sums.
Lines 23–48: Include the driver code containing 7 test cases that test the algorithm on various boundary conditions.
lines 24–41: the nums
list contains different test cases that represent different edge cases or typical scenarios.
lines 43–48: for each test case, it prints the input values (nums, target
) and the number of unique combinations found by combination_sum()
.
Note: In the above example, the integer data type is just taken for the sake of understanding. The problem presented to you during your interview can consist of strings, floating points, boolean values, or even special characters. So be prepared for that!
Creating good test cases requires attention to detail and awareness of potential pitfalls. Here are some common mistakes to look out for:
Ignoring edge cases: Ignoring edge cases when creating test cases can lead to missed bugs. Always test scenarios like empty arrays, single-element arrays, and maximum-sized arrays.
Overlooking input constraints: To avoid potential failures, ensure your solution handles inputs at the minimum and maximum limits.
Writing too few test cases: Writing too few test cases can also be problematic. For comprehensive coverage, cover typical cases, edge cases, and performance tests.
Focusing only on positive test cases: Focusing only on positive test cases is insufficient. Include negative test cases to ensure your solution handles invalid inputs gracefully.
Regular practice is important for writing good test cases. We recommend solving common interview problems to familiarize yourself with various scenarios. Use code testing widgets from platforms like Educative, LeetCode, and HackerRank to write and run test cases adeptly. Review the given problems and their test cases to learn different approaches and challenge yourself with more complex problems to continuously improve your skills.
For example, in the dynamic programming series shown below, we present problems that can be solved using three different approaches: recursion, top-down, and bottom-up. To test each solution, we have provided a specific test case that fails on the recursive approach, but the same test case passes on the top-down and bottom-up approaches. Each test case is carefully designed on different equivalence classes and boundary values. This is a classical example of validating a solution’s correctness in different circumstances.
Writing good test cases is an important and much-needed skill in coding interviews. By thoroughly understanding the problem, considering different types of test cases, and avoiding common mistakes, you can effectively demonstrate your problem-solving abilities.
Practice regularly and take advantage of online coding platforms to improve test case creation skills and boost interview performance.
Ready to practice creating equivalence classes? Head over to the Grokking the Coding Interview Patterns course and try designing your test cases for the Subsets problem as discussed today.
Free Resources