P.Peev
P.Peev

Reputation: 13

Random strings with given length unit testing

I have a program that is generating pseudo random numbers(Only lowercase, uppercase and digits are allowed).

/**
 * 
 * @return - returns a random digit (from 0 to 9)
 * 
 */
int randomDigits() {

    return (int) (Math.random() * 10);
}

/**
 * 
 * @return - returns a random lowercase (from "a" to "z")
 */
char randomLowerCase() {

    return (char) ('a' + Math.random() * 26);
}

/**
 * 
 * @return - returns a random uppercase (from "A" to "Z")
 */
char randomUpperCase() {

    return (char) ('A' + Math.random() * 26);
}

/**
 * 
 * @return - returns a random number between 1 and 3.
 * 
 */
char randomChoice() {

    return (char) ((char) (Math.random() * 3) + 1);
}

/**
 * 
 * @param length
 *            - the length of the random string.
 * @return - returns a combined random string. All elements are builder side
 *         by side.
 * 
 *         We use the randomChoice method to get randomly upper, lower and
 *         digits.
 */
public String stringBuilder(int length) {
    StringBuilder result = new StringBuilder();
    int len = length;

    for (int i = 0; i < len; i++) {
        int ch = randomChoice();
        if (ch == 1) {
            result.append(randomDigits());
        }
        if (ch == 2) {
            result.append(randomLowerCase());
        }
        if (ch == 3) {
            result.append(randomUpperCase());

        }
    }
    return result.toString();

}

How can i make a test for that code. I try to test the range for the digits (form 0 to 9)

    int minRange = 0;
    int maxRange = 0;

    for (int i = 0; i < 100000; i++) {
        int result = item.randomDigits();
        if (result == 52) {
            minRange++;

        } else {
            if (result == 19) {
                maxRange++;

            }
        }
    }
    LOGGER.info("The min range in the digit is 0, and in the test appeared: {}", minRange);
    LOGGER.info("The max range in the digit is 9, and in the test appeared: {}", maxRange);

But i cant find how to test the lower or upper?

Upvotes: 1

Views: 6160

Answers (2)

sprinter
sprinter

Reputation: 27976

Testing code which uses any randomness is tricky. There are two approaches you can take:

  1. Your test can have sufficient iterations that it has a good chance to show any errors in your logic. For many cases iterating 1000 or 1000000 times and checking consistency of the answers is reasonable. This is your only option if you are also looking to check some required distribution across a range.

This might look something like:

for (int i = 0; i < 1000000; i++)
    assertTrue(isValid(new RandomVal()));

If you want to check that all your characters appear at least once:

assertEquals(26 * 2 + 9, IntStream.range(0, 1000000)
    .mapToObj(n -> stringBuilder(6))
    .flatMap(String::chars)
    .collect(Collectors.toSet())
    .size());

This uses Java 8 and essentially adds every character (as an integer) to the set and then checks how large it is afterwards.

  1. Using a mocking framework (such as Mockito) to check the result is the expected one for specific outputs from whatever you are using to generate randomness. This is the best way to test that you get the correct result boundary conditions (i.e. the generator returning results at each end of its range).

This might look something like:

Random mockRandom = mock(Random.class);
when(mockRandom.nextFloat()).thenReturn(0.0f);
assertTrue(isValid(new RandomVal(mockRandom));
when(mockRandom.nextFloat()).thenReturn(1.0f - Float.MIN_VALUE);
assertTrue(isValid(new RandomVal(mockRandom));

For completeness it's worth doing both of these.

Upvotes: 2

marekzbrzozowa
marekzbrzozowa

Reputation: 392

If I understand your problem resolution is simple

    int minRange =  999999; //improbable big value
    int maxRange = -999999; //improbable low value

    for (int i = 0; i < 100000; i++) {
        int result = item.randomDigits();
        minRange = Math.min(result, minRange);
        maxRange = Math.max(result, maxRange);
    }

Please try it. If you don't like Math library you can of course do it without it

    for (int i = 0; i < 100000; i++) {
        int result = item.randomDigits();
        if (result < minRange) {
            minRange = result;
        }
        if (result > maxRange) {
            maxRange = result;
        }
    }

Upvotes: -1

Related Questions