Random Numbers


The class Math provides the method random to return a pseudorandom double between 0.0 and 1.0. A number in this range may be all you need. The generated number is not truly randomthe elements of a sequence of pseudorandom numbers are only approximately independent from each other.[4] For most applications, this is sufficient.

[4] http://en.wikipedia.org/wiki/Pseudo-random_number_generator.

The class java.util.Random is a more comprehensive solution for generating pseudorandom numbers. It produces pseudorandom sequences of booleans, bytes, ints, longs, floats, Gaussians, or doubles. A pseudorandom sequence generator is not purely random; it is instead based upon an arithmetical algorithm.

You can create a Random instance with or without a seed. A seed is essentially a unique identifier for a random sequence. Two Random objects created with the same seed will produce the same sequence of values. If you create a Random object without explicitly specifying a seed, the class uses the system clock as the basis for the seed.[5]

[5] Which means that if you construct two Random objects and the construction happens to execute in the same nanosecond, you get the same sequence in both. In earlier versions of Java, the Random constructor used the current system time in milliseconds. This increased granularity significantly increased the likelihood of two Random objects having the same sequence.

You could create a simulation of coin flips through repeated use of the nextBoolean method on Random. A TRue value would indicate heads and a false value would indicate tails. The below test shows use of the seed value to produce two identical pseudorandom coin-flip sequences.

 public void testCoinFlips() {    final long seed = 100L;    final int total = 10;    Random random1 = new Random(seed);    List<Boolean> flips1 = new ArrayList<Boolean>();    for (int i = 0; i < total; i++)       flips1.add(random1.nextBoolean());    Random random2 = new Random(seed);    List<Boolean> flips2 = new ArrayList<Boolean>();    for (int i = 0; i < total; i++)       flips2.add(random2.nextBoolean());    assertEquals(flips1, flips2); } 

The methods nextInt, nexTDouble, nextLong, and nextFloat work similarly. An additional version of nextInt takes as a parameter a maximum value, such that the method always returns a number from 0 through the maximum value.

Testing Random Code

There are a few ways to write unit tests against code that must use random sequences. One way is to provide a subclass implementation of the Random class and substitute that for the Random class used in the code. The substitute Random class will provide a known sequence of values. This technique is known as mocking the Random class. I will cover mocking in considerable depth later.

In Lesson 8, you provided your own logging Handler class solely for purposes of testing. This was also a form of mocking.


You must assign passwords to students so they can access their accounts online. Passwords are eight characters long. Each character of the password must fall in a certain character range.

 package sis.util; import junit.framework.*; public class PasswordGeneratorTest extends TestCase {    public void testGeneratePassword() {       PasswordGenerator generator = new PasswordGenerator();       generator.setRandom(new MockRandom('A'));       assertEquals("ABCDEFGH", generator.generatePassword());       generator.setRandom(new MockRandom('C'));       assertEquals("CDEFGHIJ", generator.generatePassword());    } } 

The test method testGeneratePassword sets the random variable into the PasswordGenerator class to point to an instance of MockRandom. The MockRandom class extends from the Random class. The Java API documentation explains how to properly extend the Random class by overriding the method next(int bits) to return a random number based on a bit sequence. All other methods in the Random class are based on this method.

The mock implementation takes an int representing a starting character value as a parameter to its constructor. It uses this to calculate an initial value for the random sequence and stores it as i. The initial value is a number relative to the lowest valid character in the password. Its next(int bits) method simply returns and then increments the value of i.

 package sis.util; import junit.framework.*; public class PasswordGeneratorTest extends TestCase {    ...    class MockRandom extends java.util.Random {       private int i;       MockRandom(char startCharValue) {          i = startCharValue - PasswordGenerator.LOW_END_PASSWORD_CHAR;       }       protected int next(int bits) {          return i++;       }    } } 

MockRandom is defined completely within PasswordGeneratorTest. It is a nested class of PasswordGenerator. You can directly instantiate Mock-Random from within PasswordGeneratorTest, but not from any other class. There are additional kinds of nested classes, each kind with its own nuances. In Lesson 11, you will learn about nested classes in depth. Until then, use them with caution.

The implementation of PasswordGenerator follows.

 package sis.util; import java.util.*; public class PasswordGenerator {    private String password;    private static final int PASSWORD_LENGTH = 8;    private Random random = new Random();    static final char LOW_END_PASSWORD_CHAR = 48;    static final char HIGH_END_PASSWORD_CHAR = 122;    void setRandom(Random random) {       this.random = random;    }    public String generatePassword() {       StringBuffer buffer = new StringBuffer(PASSWORD_LENGTH);       for (int i = 0; i < PASSWORD_LENGTH; i++)          buffer.append(getRandomChar());       return buffer.toString();    }    private char getRandomChar() {       final char max = HIGH_END_PASSWORD_CHAR - LOW_END_PASSWORD_CHAR;       return (char)(random.nextInt(max) + LOW_END_PASSWORD_CHAR);    }    public String getPassword() {       return password;    } } 

Note that if the package-level setRandom method is not called, the random instance variable keeps its initialized value of a legitimate java.util.Random instance. Since MockRandom meets the contract of java.util.Random, you can substitute an instance of MockRandom for Random for purposes of testing.

The goal of testGeneratePassword is to prove that the PasswordGenerator class can generate and return a random password. The test does not need to reprove the functionality inherent in the Random class, but the test does need to prove that a PasswordGenerator object interacts with a Random instance (or subclass instance) through its published interface, nextInt(int max). The test must also prove that PasswordGenerator uses the nextInt return value properly. In this example, PasswordGenerator uses the nextInt return value to help construct an 8-character String of random values.

Java supplies an additional random class, java.util.SecureRandom, as a standards-based, cryptographically strong pseudorandom number generator.

Figure 10.1. Mocking the Random Class




Agile Java. Crafting Code with Test-Driven Development
Agile Javaв„ў: Crafting Code with Test-Driven Development
ISBN: 0131482394
EAN: 2147483647
Year: 2003
Pages: 391
Authors: Jeff Langr

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net