|
From: Steve F. <sm...@us...> - 2002-08-07 21:53:47
|
Update of /cvsroot/mockobjects/no-stone-unturned/doc/xdocs
In directory usw-pr-cvs1:/tmp/cvs-serv11406/doc/xdocs
Modified Files:
random.xml
Log Message:
added Nat's random chapter
Index: random.xml
===================================================================
RCS file: /cvsroot/mockobjects/no-stone-unturned/doc/xdocs/random.xml,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- random.xml 7 Aug 2002 17:21:52 -0000 1.1
+++ random.xml 7 Aug 2002 21:53:44 -0000 1.2
@@ -1,161 +1,159 @@
-<?xml version="1.0"?>
-
<chapter>
-<title>Random Acts</title>
-
-<section>
-<title>Introduction</title>
-
-<remark>Expand this</remark>
-
-<para>
-Pseudo-random behaviour is used in many applications.
-In games it is used to portray natural behaviours that are too complex to
-simulate accurately, or to add variety to behaviours that are too predictable
-when simulated algorithmically.
-</para>
-
-<para>
-How do we test randomness?
-</para>
-
-</section>
-
-<section>
-<title>Come Rain...</title>
-
-<para>
-I have been contracted to write a game that simulates the strategy of
-Formula One motor racing.
-My customer tells me that the weather plays has an important effect on
-F1 strategy, so my game will have to simulate the weather somehow.
-However, she wants the game to run in a web browser, and that means
-writing it as a Java applet.
-I'm going to rule out a realistic weather simulation — I'm going to
-need all those CPU cycles to simulate the cars and drivers — and
-instead randomly generate weather effects.
-</para>
-
-<para>
-The first story I have is that the player must choose different tyres
-depending on whether it is raining or not. Most of the time it will
-be sunny but it should rain on every one out of every five races,
-chosen at random.
-Time to write a test, but how do I test a random event?
-The weather object is obviously going to use a random number generator
-to test the probability of rain. If that random number generator is
-completely encapsulated within the weather object, I cannot override
-the randomness to cause the behaviour I want to test.
-Therefore, I need to mock that random number generator in my tests to
-feed in fixed values, and pass the random number generator to the
-weather object's constructor.
-</para>
-
-<programlisting lang="java">public void testRandomRain() {
- MockRandom rng = new MockRandom();
-
- Weather weather = new Weather( rng );
-
- rng.setNextDouble( 0.0 );
- weather.randomize();
- assertTrue( "is raining", weather.isRaining() );
-
- rng.setNextDouble( Weather.CHANCE_OF_RAIN );
- weather.randomize();
- assertTrue( "is not raining", !weather.isRaining() );
-
- rng.setNextDouble( 1.0 );
- weather.randomize();
- assertTrue( "is not raining", !weather.isRaining() );
-}</programlisting>
+ <title>Random Acts</title>
-<para>
-Here's the <classname>MockRandom</classname> class used by the test:
-</para>
+ <section>
+ <title>Introduction</title>
+ <remark>Expand this</remark>
+
+ <para>
+ Pseudo-random behaviour is used in many applications.
+ In games it is used to portray natural behaviours that are too complex to
+ simulate accurately, or to add variety to behaviours that are too predictable
+ when simulated algorithmically.
+ </para>
+
+ <para>
+ How do we test randomness?
+ </para>
+
+ </section> <!-- Introduction -->
+
+ <section>
+ <title>Come Rain...</title>
+
+ <para>
+ I have been contracted to write a game that simulates the strategy of
+ Formula One motor racing.
+ My customer tells me that the weather plays has an important effect on
+ F1 strategy, so my game will have to simulate the weather somehow.
+ However, she wants the game to run in a web browser, and that means
+ writing it as a Java applet.
+ I'm going to rule out a realistic weather simulation — I'm going to
+ need all those CPU cycles to simulate the cars and drivers — and
+ instead randomly generate weather effects.
+ </para>
+
+ <para>
+ The first story I have is that the player must choose different tyres
+ depending on whether it is raining or not. Most of the time it will
+ be sunny but it should rain on every one out of every five races,
+ chosen at random.
+ Time to write a test, but how do I test a random event?
+ The weather object is obviously going to use a random number generator
+ to test the probability of rain. If that random number generator is
+ completely encapsulated within the weather object, I cannot override
+ the randomness to cause the behaviour I want to test.
+ Therefore, I need to mock that random number generator in my tests to
+ feed in fixed values, and pass the random number generator to the
+ weather object's constructor.
+ </para>
+
+ <programlisting lang="java">
+public void testRandomRain() {
+ MockRandom rng = new MockRandom();
+
+ Weather weather = new Weather( rng );
+
+ rng.setNextDouble( 0.0 );
+ weather.randomize();
+ assertTrue( "is raining", weather.isRaining() );
+
+ rng.setNextDouble( Weather.CHANCE_OF_RAIN );
+ weather.randomize();
+ assertTrue( "is not raining", !weather.isRaining() );
+
+ rng.setNextDouble( 1.0 );
+ weather.randomize();
+ assertTrue( "is not raining", !weather.isRaining() );
+}</programlisting>
+
+ <para>
+ Here's the <classname>MockRandom</classname> class used by the test:
+ </para>
-<programlisting>public class MockRandom
- extends Random
+ <programlisting>
+public class MockRandom extends Random
{
private double nextDouble = 0.0;
-
+
public void setNextDouble( double d ) {
nextDouble = d;
}
-
+
public double nextDouble() {
return nextDouble;
}
-}
-</programlisting>
+}</programlisting>
-<para>
-And now we can write a Weather class that passes the tests:
-</para>
+ <para>
+ And now we can write a Weather class that passes the tests:
+ </para>
-<programlisting lang="java">public class Weather
+ <programlisting lang="java">
+public class Weather
{
public static double CHANCE_OF_RAIN = 0.2;
-
-
+
+
private Random rng;
private boolean isRaining = false;
-
+
public Weather( Random rng ) {
this.rng = rng;
}
-
+
public boolean isRaining() {
return isRaining;
}
-
+
public void randomize() {
- isRaining = rng.nextDouble() < CHANCE_OF_RAIN;
+ isRaining = rng.nextDouble() < CHANCE_OF_RAIN;
}
}</programlisting>
-</section>
+ </section> <!-- Come rain -->
+ <section>
+ <title>...Or Shine</title>
-<section>
-<title>...Or Shine</title>
-
-<para>My customer now tells me that ground temperature is also
-important to race strategy.
-The player should choose different tyre compounds depending on the
-temperature. Now my weather object must choose a temperature and whether
-it is raining, both at random.
-The random temperature will be chosen from a range of 20°C and 30°C.
-But, the ground should be on average half the temperature when it is raining
-compared to when it is sunny.
-</para>
-
-<para>
-Again, let's write a test. Actually, I think we need
-two tests, one to test that the temperature
-is selected from within the forecast range when it is sunny,
-and another to test that it is half the sunny temperature when raining.
-Let's start with the former. Again we need to mock the random number
-generator, but this time the <methodname>randomize</methodname> method
-will get <emphasis>two</emphasis> random numbers. We need to change our
-<classname>MockRandom</classname> class to mock a stream of random
-numbers, rather than just one:
-</para>
+ <para>
+ My customer now tells me that ground temperature is also
+ important to race strategy.
+ The player should choose different tyre compounds depending on the
+ temperature. Now my weather object must choose a temperature and whether
+ it is raining, both at random.
+ The random temperature will be chosen from a range of 20°C and 30°C.
+ But, the ground should be on average half the temperature when it is raining
+ compared to when it is sunny.
+ </para>
+
+ <para>
+ Again, let's write a test. Actually, I think we need
+ two tests, one to test that the temperature
+ is selected from within the forecast range when it is sunny,
+ and another to test that it is half the sunny temperature when raining.
+ Let's start with the former. Again we need to mock the random number
+ generator, but this time the <methodname>randomize</methodname> method
+ will get <emphasis>two</emphasis> random numbers. We need to change our
+ <classname>MockRandom</classname> class to mock a stream of random
+ numbers, rather than just one:
+ </para>
-<programlisting>public class MockRandom
- extends Random
+ <programlisting>
+public class MockRandom extends Random
{
private double[] nextDoubles = {0.0};
private int nextIndex = 0;
-
+
public void setNextDouble( double d ) {
setNextDoubles( new double[]{ d } );
}
-
+
public void setNextDoubles( double[] d ) {
nextDoubles = d;
nextIndex = 0;
}
-
+
public double nextDouble() {
double result = nextDoubles[nextIndex];
nextIndex = (nextIndex + 1) % nextDoubles.length;
@@ -163,18 +161,19 @@
}
}</programlisting>
-<para>
-Ok, the new <classname>MockRandom</classname> doesn't affect our existing
-tests, so we can go on to write the test for random temperature when sunny:
-</para>
+ <para>
+ Ok, the new <classname>MockRandom</classname> doesn't affect our existing
+ tests, so we can go on to write the test for random temperature when sunny:
+ </para>
-<programlisting>public void testRandomTemperatureSunny() {
+ <programlisting>
+public void testRandomTemperatureSunny() {
MockRandom rng = new MockRandom();
final double SUNNY = 1.0;
-
+
Weather weather = new Weather( rng );
-
+
rng.setNextDoubles( new double[] { SUNNY, 0.0 } );
weather.randomize();
assertEquals( "should be min temperature",
@@ -192,56 +191,58 @@
Weather.MAX_TEMPERATURE, weather.getTemperature(), 0.0 );
}</programlisting>
-<para>
-And write code to pass that test:
-</para>
+ <para>
+ And write code to pass that test:
+ </para>
-<programlisting>public class Weather
+ <programlisting>
+public class Weather
{
public static double CHANCE_OF_RAIN = 0.2;
<emphasis>public static double MIN_TEMPERATURE = 20;
public static double MAX_TEMPERATURE = 30;</emphasis>
-
+
private Random rng;
private boolean isRaining = false;
<emphasis>private double temperature = MIN_TEMPERATURE;</emphasis>
-
- public Weather( Random rng ) {
- this.rng = rng;
+
+ public Weather( Random aRng ) {
+ rng = aRng;
}
-
+
public boolean isRaining() {
return isRaining;
}
-
+
<emphasis>public double getTemperature() {
return temperature;
}</emphasis>
-
+
public void randomize() {
- isRaining = rng.nextDouble() < CHANCE_OF_RAIN;
- <emphasis>temperature = MIN_TEMPERATURE +
+ isRaining = rng.nextDouble() < CHANCE_OF_RAIN;
+ <emphasis>temperature = MIN_TEMPERATURE +
rng.nextDouble() * (MAX_TEMPERATURE-MIN_TEMPERATURE);</emphasis>
}
}</programlisting>
-<para>
-Now for the temperature when it is raining. The test will look very similar
-the the one I just wrote, except that it expect the temperatures to be
-half those when sunny.
-</para>
+ <para>
+ Now for the temperature when it is raining. The test will look very similar
+ the the one I just wrote, except that it expect the temperatures to be
+ half those when sunny.
+ </para>
-<programlisting>public void testRandomTemperatureRaining() {
+ <programlisting>
+public void testRandomTemperatureRaining() {
MockRandom rng = new MockRandom();
final double RAIN = 0.0;
-
+
Weather weather = new Weather( rng );
-
+
rng.setNextDoubles( new double[] { RAIN, 0.0 } );
weather.randomize();
assertEquals( "should be min rainy temperature",
Weather.MIN_TEMPERATURE/2, weather.getTemperature(), 0.0 );
-
+
rng.setNextDoubles( new double[] { RAIN, 0.5 } );
weather.randomize();
assertEquals( "should be average rainy temperature",
@@ -254,63 +255,67 @@
Weather.MAX_TEMPERATURE/2, weather.getTemperature(), 0.0 );
}</programlisting>
-<para>
-Now I'll change the <classname>Weather</classname>'s
-<methodname>randomize</methodname> to half the temperature when it is raining:
-</para>
-
-<programlisting>public void randomize() {
- temperature = MIN_TEMPERATURE +
+ <para>
+ Now I'll change the <classname>Weather</classname>'s
+ <methodname>randomize</methodname> to half the temperature when it is raining:
+ </para>
+
+ <programlisting>
+public void randomize() {
+ temperature = MIN_TEMPERATURE +
rng.nextDouble() * (MAX_TEMPERATURE-MIN_TEMPERATURE);
-
- isRaining = rng.nextDouble() < CHANCE_OF_RAIN;
+
+ isRaining = rng.nextDouble() < CHANCE_OF_RAIN;
if( isRaining ) temperature *= 0.5;
}</programlisting>
-<para>That was easy! I'll just run my tests and... whoops! The
-<methodname>testRandomTemperatureRaining</methodname> test failed.
-Not only that, my <methodname>testRandomTemperatureSunny</methodname> test
-failed as well! Why did that happen? The behaviour I added to the
-<methodname>randomize</methodname> method should not have had an affect
-when it was not raining.
-</para>
-
-</section>
-
-<section>
-<title>Test Smell: Order Shouldn't Matter</title>
-
-<para>Actually, looking at it again, I realise that I swapped the order
-of that statements that randomized the rain and temperature.
-The tests now initialise the stream of mock random numbers in the wrong
-order. This is not good: tests should not be tied to the internal
-implementation details of the class. They should specify only its externally
-visible behaviour. How can I make my tests less brittle?
-</para>
-
-<para>
-There should not be any externally visible dependency between randomising
-the temperature and randomising the rain. A way to remove the dependency
-is to pass <emphasis>two</emphasis> random number generators to the
-<classname>Weather</classname> class, one for the temperature and one for
-the rain. My tests can then mock each generator independently to force
-a particular outcome, no matter what order the <classname>Weather</classname>
-samples the generators. Here's the last test rewritten with two generators:
-</para>
+ <para>
+ That was easy! I'll just run my tests and... whoops! The
+ <methodname>testRandomTemperatureRaining</methodname> test failed.
+ Not only that, my <methodname>testRandomTemperatureSunny</methodname> test
+ failed as well! Why did that happen? The behaviour I added to the
+ <methodname>randomize</methodname> method should not have had an affect
+ when it was not raining.
+ </para>
+
+ </section> <!-- Come shine -->
+
+ <section>
+ <title>Test Smell: Order Shouldn't Matter</title>
+
+ <para>
+ Actually, looking at it again, I realise that I swapped the order
+ of that statements that randomized the rain and temperature.
+ The tests now initialise the stream of mock random numbers in the wrong
+ order. This is not good: tests should not be tied to the internal
+ implementation details of the class. They should specify only its externally
+ visible behaviour. How can I make my tests less brittle?
+ </para>
+
+ <para>
+ There should not be any externally visible dependency between randomising
+ the temperature and randomising the rain. A way to remove the dependency
+ is to pass <emphasis>two</emphasis> random number generators to the
+ <classname>Weather</classname> class, one for the temperature and one for
+ the rain. My tests can then mock each generator independently to force
+ a particular outcome, no matter what order the <classname>Weather</classname>
+ samples the generators. Here's the last test rewritten with two generators:
+ </para>
-<programlisting>public void testRandomTemperatureRaining() {
+ <programlisting>
+public void testRandomTemperatureRaining() {
<emphasis>MockRandom rain_rng = new MockRandom();
rain_rng.setNextDouble(0.0);
-
+
MockRandom temp_rng = new MockRandom();
-
+
Weather weather = new Weather( rain_rng, temp_rng );
-
+
temp_rng.setNextDouble( 0.0 );</emphasis>
weather.randomize();
assertEquals( "should be min rainy temperature",
Weather.MIN_TEMPERATURE/2, weather.getTemperature(), 0.0 );
-
+
<emphasis>temp_rng.setNextDouble( 0.5 );</emphasis>
weather.randomize();
assertEquals( "should be average rainy temperature",
@@ -323,158 +328,162 @@
Weather.MAX_TEMPERATURE/2, weather.getTemperature(), 0.0 );
}</programlisting>
-<para>
-I can rewrite the <methodname>testRandomTemperatureSunny</methodname>
-test in a similar way and I also have to change the
-<methodname>testRandomRain</methodname> test to instantiate the
-<classname>Weather</classname> object with two random number generators;
-we'll skip over the code to save trees.
-</para>
-
-<para>
-Now I have failing tests for the behaviour I want to implement, so I
-need to change my Weather class to use two random number generators:
-</para>
+ <para>
+ I can rewrite the <methodname>testRandomTemperatureSunny</methodname>
+ test in a similar way and I also have to change the
+ <methodname>testRandomRain</methodname> test to instantiate the
+ <classname>Weather</classname> object with two random number generators;
+ we'll skip over the code to save trees.
+ </para>
+
+ <para>
+ Now I have failing tests for the behaviour I want to implement, so I
+ need to change my Weather class to use two random number generators:
+ </para>
-<programlisting>public class Weather
+ <programlisting>
+public class Weather
{
public static double CHANCE_OF_RAIN = 0.2;
public static double MIN_TEMPERATURE = 20; // degrees C
public static double MAX_TEMPERATURE = 30; // degrees C
-
+
<emphasis>private Random tempRandom, rainRandom;</emphasis>
private boolean isRaining = false;
private double temperature = MIN_TEMPERATURE;
-
+
<emphasis>public Weather( Random rainRandom, Random tempRandom ) {
this.tempRandom = tempRandom;
this.rainRandom = rainRandom;
}</emphasis>
-
+
[...]
-
+
public void randomize() {
- temperature = MIN_TEMPERATURE +
+ temperature = MIN_TEMPERATURE +
<emphasis>tempRandom</emphasis>.nextDouble() * (MAX_TEMPERATURE-MIN_TEMPERATURE);
-
- isRaining = <emphasis>rainRandom</emphasis>.nextDouble() < CHANCE_OF_RAIN;
+
+ isRaining = <emphasis>rainRandom</emphasis>.nextDouble() < CHANCE_OF_RAIN;
if( isRaining ) temperature *= 0.5;
}
}</programlisting>
-<tip>
-Only test the order in which an object calls methods of other objects
-if that is an important aspect of your object's publically visible
-behaviour. If it is unimportant, your tests will be brittle if your
-they expect one particular order.
-</tip>
-
-<para>
-Finally, my <classname>MockRandom</classname> class now contains behaviour
-that I don't use, and that I've realised is a bad idea. I'll discard
-that code by restoring the original version of the class from my source
-code repository.
-</para>
-
-</section>
-
-
-<section>
-<title>Refactoring: Too Many Arguments</title>
-<para>
-My customer is happy. However, she tells me, in Formula One, teams
-use tyres with different treads depending on how wet the track is, so
-our weather class needs to simulate both if it is raining, and
-how wet the track is. Another important element of Formula One strategy
-is changing tyres when the weather changes, so the rain should start and
-stop at random intervals, and the track should become wetter when it is
-raining and dry off when it is sunny.
-</para>
-
-<para>
-All this is straightforward to implement, but my nose is twitching:
-my code, although functional, is smelly.
-I can foresee that as I add functionality to the
-<classname>Weather</classname> class, the implementation will become
-increasingly awkward because there will be too many random number generators.
-In particular each time I add more random behaviour I will have to change
-all the tests because the signature of the constructor will have changed,
-and the constructor will end up with far too many parameters:
-</para>
+ <tip>
+ Only test the order in which an object calls methods of other objects
+ if that is an important aspect of your object's publically visible
+ behaviour. If it is unimportant, your tests will be brittle if your
+ they expect one particular order.
+ </tip>
+
+ <para>
+ Finally, my <classname>MockRandom</classname> class now contains behaviour
+ that I don't use, and that I've realised is a bad idea. I'll discard
+ that code by restoring the original version of the class from my source
+ code repository.
+ </para>
+
+ </section> <!-- Test Smell -->
+
+ <section>
+ <title>Refactoring: Too Many Arguments</title>
+ <para>
+ My customer is happy. However, she tells me, in Formula One, teams
+ use tyres with different treads depending on how wet the track is, so
+ our weather class needs to simulate both if it is raining, and
+ how wet the track is. Another important element of Formula One strategy
+ is changing tyres when the weather changes, so the rain should start and
+ stop at random intervals, and the track should become wetter when it is
+ raining and dry off when it is sunny.
+ </para>
+
+ <para>
+ All this is straightforward to implement, but my nose is twitching:
+ my code, although functional, is smelly.
+ I can foresee that as I add functionality to the
+ <classname>Weather</classname> class, the implementation will become
+ increasingly awkward because there will be too many random number generators.
+ In particular each time I add more random behaviour I will have to change
+ all the tests because the signature of the constructor will have changed,
+ and the constructor will end up with far too many parameters:
+ </para>
-<programlisting>public Weather( Random rainRandom, Random tempRandom, Random wetnessRandom,
+ <programlisting>
+public Weather( Random rainRandom, Random tempRandom, Random wetnessRandom,
Random rainDurationRandom, Random dryDurationRandom )
{
[...]
}</programlisting>
-<para>
-I recognise this "code smell". Every time I see a method that takes a lot
-of arguments, I know that there is a new concept waiting to be extracted.
-Just as the method
-<methodname>drawRectangle( int x, int y, int width, int height )</methodname>
-indicates that a Rectangle class should be factored out and the method
-replaced by <methodname>draw( Rectangle r )</methodname>, so all those
-<classname>Random</classname> arguments indicate that there is an
-weather-specific source of randomness waiting to be extracted.
-It's time to don my refactoring hat and clear up this mess now;
-leaving it any later will just make more work. The first thing I need
-to do is define an interface for a weather-specific source of randomness:
-</para>
+ <para>
+ I recognise this "code smell". Every time I see a method that takes a lot
+ of arguments, I know that there is a new concept waiting to be extracted.
+ Just as the method
+ <methodname>drawRectangle( int x, int y, int width, int height )</methodname>
+ indicates that a Rectangle class should be factored out and the method
+ replaced by <methodname>draw( Rectangle r )</methodname>, so all those
+ <classname>Random</classname> arguments indicate that there is an
+ weather-specific source of randomness waiting to be extracted.
+ It's time to don my refactoring hat and clear up this mess now;
+ leaving it any later will just make more work. The first thing I need
+ to do is define an interface for a weather-specific source of randomness:
+ </para>
-<programlisting>public interface WeatherRandom
+ <programlisting>
+public interface WeatherRandom
{
boolean nextIsRaining();
double nextTemperature();
}</programlisting>
-<para>
-I don't have to implement this interface right now.
-I can test the <classname>Weather</classname> class by mocking the interface,
-and then test and write an implementation once the
-<classname>Weather</classname> tests are passing.
-Our new <classname>WeatherRandom</classname> class simplifies our tests
-greatly. We no longer have to test that the <classname>Weather</classname>
-class compares probabilities against random numbers correctly; that will
-be the responsibility of the real implementation of
-<classname>WeatherRandom</classname>. Instead we just have to test that
-the <classname>Weather</classname> class stores the random weather and
-calculates a cooler temperature when it is raining. Here's our
-<methodname>testRandomTemperatureRaining</methodname> test:
-</para>
+ <para>
+ I don't have to implement this interface right now.
+ I can test the <classname>Weather</classname> class by mocking the interface,
+ and then test and write an implementation once the
+ <classname>Weather</classname> tests are passing.
+ Our new <classname>WeatherRandom</classname> class simplifies our tests
+ greatly. We no longer have to test that the <classname>Weather</classname>
+ class compares probabilities against random numbers correctly; that will
+ be the responsibility of the real implementation of
+ <classname>WeatherRandom</classname>. Instead we just have to test that
+ the <classname>Weather</classname> class stores the random weather and
+ calculates a cooler temperature when it is raining. Here's our
+ <methodname>testRandomTemperatureRaining</methodname> test:
+ </para>
-<programlisting>public void testRandomTemperatureRaining() {
+ <programlisting>
+public void testRandomTemperatureRaining() {
final double TEMPERATURE = 20;
-
+
MockWeatherRandom rng = new MockWeatherRandom() {
public boolean nextIsRaining() { return true; }
public double nextTemperature() { return TEMPERATURE; }
};
-
+
Weather weather = new Weather( rng );
-
+
weather.randomize();
- assertEquals( "temperature",
+ assertEquals( "temperature",
TEMPERATURE/2.0, weather.getTemperature(), 0.0 );
}</programlisting>
-<para>
-Now I have to modify the <classname>Weather</classname> class to
-use a <classname>WeatherRandom</classname> to pass the tests:
-</para>
+ <para>
+ Now I have to modify the <classname>Weather</classname> class to
+ use a <classname>WeatherRandom</classname> to pass the tests:
+ </para>
-<programlisting>public class Weather
+ <programlisting>
+public class Weather
{
<emphasis>private WeatherRandom random;</emphasis>
private boolean isRaining = false;
private double temperature = 0.0;
-
+
<emphasis>public Weather( WeatherRandom random ) {
this.random= random;
}</emphasis>
-
+
[...]
-
+
public void randomize() {
<emphasis>temperature = random.nextTemperature();
isRaining = random.nextIsRaining();</emphasis>
@@ -482,21 +491,22 @@
}
}</programlisting>
-<para>
-And finally I need to test and implement a real
-<classname>WeatherRandom</classname> that generates random weather
-using a random number generator.
-Each of the <classname>WeatherRandom</classname> methods can be tested
-individually using a MockRandom object, just as we did in our earlier
-tests of the <classname>Weather</classname> class. Because each method
-makes one call to the random number generator, no internal
-implementation details leak out into our tests.
-</para>
+ <para>
+ And finally I need to test and implement a real
+ <classname>WeatherRandom</classname> that generates random weather
+ using a random number generator.
+ Each of the <classname>WeatherRandom</classname> methods can be tested
+ individually using a MockRandom object, just as we did in our earlier
+ tests of the <classname>Weather</classname> class. Because each method
+ makes one call to the random number generator, no internal
+ implementation details leak out into our tests.
+ </para>
-<programlisting>public void testNextIsRaining() {
+ <programlisting>
+public void testNextIsRaining() {
MockRandom rng = new MockRandom();
WeatherRandom weather_random = new DefaultWeatherRandom(rng);
-
+
rng.setNextDouble( 0.0 );
assertTrue( "is raining", weather_random.nextIsRaining() );
@@ -507,15 +517,16 @@
assertTrue( "is not raining", !weather_random.nextIsRaining() );
}</programlisting>
-<para>
-I can now go on to implement the additional random behaviour requested
-by my customer. I will define each additional random effect as a method
-in the <classname>WeatherRandom</classname> interface. I will also define
-a sensible default result in the <classname>MockWeatherRandom</classname>
-so that tests that do not care about the effect do not have to be changed.
-</para>
+ <para>
+ I can now go on to implement the additional random behaviour requested
+ by my customer. I will define each additional random effect as a method
+ in the <classname>WeatherRandom</classname> interface. I will also define
+ a sensible default result in the <classname>MockWeatherRandom</classname>
+ so that tests that do not care about the effect do not have to be changed.
+ </para>
-<programlisting>public interface WeatherRandom
+ <programlisting>
+public interface WeatherRandom
{
boolean nextIsRaining();
double nextTemperature();
@@ -524,34 +535,34 @@
double nextDryDuration();</emphasis>
}</programlisting>
-</section>
+ </section> <!-- Too many arguments -->
-<section>
-<title>What Have We Learned?</title>
+ <section>
+ <title>What Have We Learned?</title>
-<remark>Expand this</remark>
+ <remark>Expand this</remark>
-<para>
-Test random behaviour by pulling the random number generator out of the
-object being tested and mocking it.
-</para>
-
-<para>
-Mocking random behaviour can expose implementation details by assuming
-how individual elements of a random number sequence will be used by
-the class under test. This breaks encapsulation and makes tests brittle.
-Avoid brittle tests by "parallelizing" your random number streams.
-Initialise your objects with multiple sources of randomness that can be
-mocked independently to test specific behaviours.
-</para>
-
-<para>
-Define application-specific random generators, rather than passing multiple
-random number generators into your class, so that changes to the random
-behaviour of your class do not cause changes to ripple through your class
-and all of its tests.
-</para>
+ <para>
+ Test random behaviour by pulling the random number generator out of the
+ object being tested and mocking it.
+ </para>
+
+ <para>
+ Mocking random behaviour can expose implementation details by assuming
+ how individual elements of a random number sequence will be used by
+ the class under test. This breaks encapsulation and makes tests brittle.
+ Avoid brittle tests by "parallelizing" your random number streams.
+ Initialise your objects with multiple sources of randomness that can be
+ mocked independently to test specific behaviours.
+ </para>
+
+ <para>
+ Define application-specific random generators, rather than passing multiple
+ random number generators into your class, so that changes to the random
+ behaviour of your class do not cause changes to ripple through your class
+ and all of its tests.
+ </para>
-</section>
+ </section> <!-- what have we learned -->
</chapter>
|