lock-openPassword Validator

Requirements: when creating a new account or resetting an old password, the new password must be at least 10 characters long, at least one uppercase character, at least one number, and one of the following special characters: !@#$%^&.

A formal, structured approach for this challenge can be found on the Classification Tree Method page. It also shows the Pairwise testing technique and the usage of the PICT tool to generate test value combinations. This is possible and probably desirable in a realistic setting at work.

But in an interview setting with possibly 10-30 minutes to offer a solution, this might not be possible. At most, you could draw a Classification Tree with pen and paper to get a structured overview before creating tests.

Non-exhaustive solution

As usual, the first thing is to analyze the given task and ASK QUESTIONS. One of the most striking assumptions is to consider "a character" to be exclusively English.

There's a plethora of non-English characters, as well as characters or signs in other languages (Chinese, Arabic, Russian, Hindi, etc.), as well as emojis taking up 4 or more bytes, and having a length of 2 or more. For example, "🚀".length in JavaScript returns 2, not 1.

We'll assume that clarification was provided that only English letter characters a-zA-Z are allowed (in addition to numbers and special characters !@#$%^&.

The bare minimum

The primary dimension of the primary variable (password) seems to be length. That is also the Boundary.

Password characteristic
Expected result

Length of 10

Accepted

Length below 10

Rejected

Length of 0 (empty)

Rejected

Extreme length (millions of characters)

Accepted? How and where is the password stored? There must be technical limitations, so what should the practical limit be?

Copy paste an extremely long password

As above. This is a variation of the same test, but it attempts to bypass functionality that limits length based on keystrokes.

If you believe that "no user will create such a long password", refer to the Assume Misuse Heuristicarrow-up-right.

The next thing is the absence of specific characters - uppercase, numbers, and one of !@#$%^&. We should follow the principle of the Elementary Comparison technique and create passwords that fail for one reason, and one reason only:

Input
Expected result

Password with no uppercase character

Rejected

Password with no number

Rejected

Password with no special character

Rejected

The next step is to use a fully valid password of length >= 10, but include invalid characters:

Input
Expected result

Space, tab, other whitespace in the middle

Rejected

Space, tab, other whitespace at start or end

Should the validator explicitly reject or quietly trim, check for length, validate, and potentially accept?

Contains emoji

Rejected

Contains latin accentuated character (e.g., á, é, í)

Rejected

Contains Chinese, Arabic, Russian, and other characters. In particular, Russian letters that LOOK the same as English ones, but are represented differently at the binary level - катом

Rejected

Contains / : [ ` {

Rejected. These characters are noteworthy for these specific requirements, because they are placed around the a-z, 0-9 and A-Z ranges in the ASCII tablearrow-up-right.

Diving deeper

What if the password validator somehow fails to detect the presence of a mandatory character, such as at least one number or one special character? Can we be satisfied with only one valid password? Shouldn't we test with all numbers 0-9 and with all special chars !@#$%^& and ALL uppercase characters A-Z?

That is 9 (numbers)+7 (special chars)+26 (AZ)=42 extra casesThat \ is \ 9 \ (numbers) + 7 \ (special \ chars) + 26 \ (A-Z) = 42 \ extra \ cases

Also, let's remember that length is the primary dimension. Therefore, FIRST and LAST characters are the boundaries. To make testing more robust, we can create passwords that include important characters at these boundaries.

While "exhaustive testing" (with respect to special characters above only) is possible, we could create a suite that balances size and the chance of finding a bug.

We can use the Beginning, Middle, Endarrow-up-right heuristic:

  • All !@#$%^& characters - the sample is small enough (7) to include all

To match their number (7), we shall pick 7 numbers and characters:

  • 0, 1, 2, 5, 6, 8, 9 for numbers

  • A, B, C, L, M, Y, Z for characters - start, middle, and end of the alphabet

Once we distribute and rotate them across password edges, we can get something as in the table below. ___ means any valid lowercase character.

Password of length ≥ 10
Expected Result

!___0___A B___@___1 2___C___# $___5___L M___%___6 8___Y___^ &___9___Z

Accepted

We get meaningful and significant additional coverage with just 7 tests.

circle-info

This is not "the only correct way" to select input. This is an example of how to balance testing effort with the potential reward (uncovering defects) and provide appropriate justification.

Additional considerations

Usability

  • Color in green when the password passes validation

  • Color in red when password fails validation + specific or generic explanation why?

Security

Password (or sensitive data) transmission, storage, retrieval, recovery, and general handling are complex topics and are out of scope for a testing exercise. In real life, these must be addressed.

Summary

As a replacement for the manual construction of tests in the "Diving Deeper" section, Pairwise could be used to generate a sample of test values with a wider range of characters. See PICT tool usagearrow-up-right.

To ensure that the most important cases are covered, one could craft special and most important cases by hand and feed them as a "seed" to the PICT tool or one of its alternatives. Then use a Pairwise tool to quickly generate dozens or even hundreds more password permutations and feed them to an automated script. With test automation, hundreds of passwords can be generated and tested in seconds. This exercise and solution demonstrate how one can identify risk and risky areas and intelligently reduce the amount of testing effort while maximizing the chance of finding a bug.

Last updated