KarelFixture
Back to the [FrontPage] [FixtureDevelopment page]
Copyright (C) 2004, Joseph Bergin. All rights reserved
This is intended to be used in conjunction with Karel J Robot. See http://csis.pace.edu/~bergin/KarelJava2ed/Karel++JavaEdition.html
If you have comments or suggestions, please leave them here: ^CommentsAndSuggestions?. I'd also like to know if you are using this.
General Concepts
KarelFixture is a means both of scripting robot actions and specifying the behavior of robots before they are built. You can create robots, open world files, send messages to robots and make assertions about their behavior.
The tests are in the form of html tables. In this system, tables are entered using a simplified syntax. http://fitnesse.org/FitNesse.UserGuide.
If a page has a test button at the left (you can turn this on or off with the properties button), then pushing the test button will execute all the code described on the page (it can take a minute or two). If a test "succeeds" its cell will be shown in green. If it fails, in red. Queries are shown in purple. If an exception is thrown by your code you will see it in a yellow cell. Some failures cause other tests to be ignored. Any textual output that your tests produce will be shown on the error log page you can reach from the bottom of the test results page.
Note that there are some limitations here. First is that it is not a graphical system in the sense that the simulator is. More important, there are some programs you can write that can't be tested here. This has not (yet) been tested with threaded robots. There are some parameter types that will not work with this system, but int, double, String, and object types should work ok.
Note also, that what you do in one table will carry over to the next. So if you open a world in the first table, it will still be in place for the rest of the page. You can give the world the reset command to clear out the results of earlier tests, of course.
At any given time there is one "current" class. The create command will create a robot in this class. Likewise there will be (at most) one current Tester class. Assert commands refer to this class. The default assert class is kareltherobot.KJRTest which is in the KarelJRobot.jar.
Most of what is here is actually more general than just Robots. This class simply adds some convenience features to GeneralFixture so as to make it a bit easier to use with Karel J Robot.
Stair Climber specification - the code for the stair climber class is included here, so you run the test to see the result.
| kareltherobot.KarelFixture | |||||
| kareltherobot.StairClimber | |||||
| Tester | kareltherobot.KJRTest | local | |||
| World | reset | ||||
| Read World | stairworld.kwld | ||||
| Create | karel | 1 | 1 | East | 0 |
| Message | karel | getBeeper | |||
| Assert | BeepersInWorld | 0 | |||
| Assert | BeepersInBeeperBag | karel | |||
| Assert | FacingEast | karel | |||
| Assert | NotRunning | karel | |||
| Assert | At | karel | 4 | 4 | |
Specification for the newspaper picker task.
Write a new robot class and an instruction to solve problem 5 of chapter 2. (There is no code here for this task.)
| KarelFixture | |||||
| kareltherobot.NewspaperPickerRobot | |||||
| Read World | newspaper.kwld | ||||
| Assert | BeepersAt | 3 | 3 | ||
| Create | karel | 3 | 4 | West | 0 |
| Message | karel | getPaper | |||
| Assert | At | karel | 3 | 4 | |
| Assert | BeepersInBeeperBag | karel | |||
| Assert | FacingWest | karel | |||
| Assert | NotRunning | karel | |||
| Assert | BeepersInWorld | 0 | |||
Setup
You first need to get a copy of this server from its source http://fitnesse.org. It is written in Java and you can run it anywhere, either on your local machine or, more usefully, on some public server.It is much more than just a test environment. It is a very nice "wiki" or Quickie Web. Every page can be edited by the visitor (subject to some restrictions). It is a great communication mechanism for courses, either online or face-to-face.
You use it by creating pages that contain your tests in the form of tables like the ones seen here. But visit http://fitnesse.org to learn the markup rules which are different, and easier, than html. Interestingly, you can write your tests in Microsoft Excel and import them here.
You will need to establish a classpath here with the !path widget. You will need KarelJRobot.jar, jbfixture.jar and any classes of your own that you would like to test. They can be in jar files or in class directories.
If you are exploring this, note that when you run a test, some replacemnt of the original contents of some cells is done (primarily by queries). For most effective learning, if you have a tabbed brower, have the original tests in one tab and the test results in another. That way you can compare before and after. Different pages works fine too.
Get the necessary files
You download the Jar files from the following links:http://csis.pace.edu:8077/files/JoeBergin/Fixtures/KarelJRobot.jar
http://csis.pace.edu:8077/files/JoeBergin/Fixtures/junit.jar
http://csis.pace.edu:8077/files/JoeBergin/Fixtures/jbfixture.jar
You need the above in addition to the fitNesse.jar available from http://fitnesse.org
Form of the Tables
Row 1
The first row always gives the name of the testing fixture. Here it is kareltherobot.KarelFixture. After the first table you can abbreviate this to KarelFixture.Row 2
The second row is the full name of some robot class. It should be kareltherobot.UrRobot? or something that extends this class. (Actually, the system is more general than that, but it is optimized for this case. For more general use see GeneralFixture. You can optionally put a second cell on this row with a name that you want to use within this system for this class. Think of it as a local abbreviation. Note however, that you will be naming several things here, including robots, and your names need to be distinct. If you define a name again, its latest definition prevails.This command establishes the current class. Until it is changed, the Create command will create robots in this class. If you name a class in one table you can use the abbreviation instead of the full name later, including in other tables.
By default the parameter interpretation for methods and constructors in this class will be set to int and double. This means that when you use a parameter in a Create command (for example) that consists of just digits, the system will assume it is either an int or an Integer. If the corresponding constructor (or method, in the general case) requires long, for example, you can put extra cells on the second row after the name cell. In these cells you can use any of byte, short, int, long, float, double. The system will then change its behavior to assume your parameters take on the given types. Note, that float and double only apply to values with a decimal point and the others only to those without. Once you set the system it will remember what you say until you change it by giving a different set in a new table, or equivalently in a Class command. If you put several such cells that conflict, such as |int|long|byte| then only the last one will be in effect, but you can set the defalults differently for things that look like integer data and things that look like floating point data. Note that the system purposly confuses the primitive types and the wrappers, so |long| works for both long and Long.
Rows 3 ... n
The rest of the rows in a table conform to the rules of any of the following commands in any order. For these rows, the first cell is the name of the command (always capitalized and if it has two words, a single space between the words). The rest of a row is determined by the individual command's requirements.Commands
Read World (read the world from a file)
parameter: A string giving a file name. It should be a valid Karel J Robot world file. The first parameter is in the first cell following a command, which is the second cell of a row. See an example above. The file must be available in the directory from which you run this server.See examples above
Save World (write the world to a file)
parameter: A string giving a file name in which to write the current contents of the world.| kareltherobot.KarelFixture | ||||
| kareltherobot.StairClimber | ||||
| World | placeBeepers | 1 | 1 | infinity |
| Save World | newworld.kwld | |||
See the note on parameters at the end.
Create (create a new robot or other object in the current class)
parameters (5 or more usually, depending on the class)(1) the name for the object (robot) you want to create
(2) the street on which to deliver the robot
(3) the avenue on which to deliver the robot
(4) the direction the robot should be facing when delivered (one of North, East, South, West)
(5) the number of beepers in the beeper bag on delivery (a non-negative integer or infinity)
See examples above. When you write your own classes, the structure must adhere to that of the constructors you write. Usually they are as above. There is currently no way to assign a color badge to a robot in this system.
If your current class is not a robot class, the parameter structure is determined by constructors for that class. There could be more or fewer than five parameters. Only the first is essential here.
Message (send a message to a robot or other object)
parameters (2 or more, depending on the message to be sent: one additional for each parameter of the message)(1) the name of the object to receive the message
(2) the message name itself, such as move or pickBeeper
(3...) any parameters that the message requires. These can be ints, booleans, Strings, or objects only). Move has no parameters, for example
(optional) At the end of the list of parameters you can put an optional empty cell. If you do this the result of sending the message will be put into this cell when you run the test. A message like move (void method) returns nothing, so the cell is filled with the word: null. If a message does return some information some String representation will be placed here. The cell is colored a shade of purple, indicating a query. For classes that derive from kareltherobot.Robot, you can see the result of sending a predicate message to a robot this way, for example.
(optional) If you place a query cell (empty) you may follow it with another cell with a string value (an abbreviation). The value returned from the message will be saved with this name for later use. See World for an example of use.
The Java Docs at http://csis.pace.edu/~bergin/KarelJava2ed/KJRdocs/ should help you see what messages you can send to the an UrRobot and a Robot (note the change in spelling of UrRobot.)
Note that if a robot crashes (executes an error turnoff) then the message that caused it will be shown in red when you test.
| KarelFixture | |||||
| kareltherobot.StairClimber | |||||
| Tester | kareltherobot.KJRTest | local | |||
| World | reset | ||||
| Read World | stairworld.kwld | ||||
| Create | karel | 1 | 1 | East | 0 |
| Message | karel | getBeeper | |||
| KarelFixture | |||||
| kareltherobot.Robot | Robot | ||||
| Create | jane | 1 | 1 | North | 3 |
| Message | jane | anyBeepersInBeeperBag | result | ||
It is important to notice that if you include the extra "naming" cell after the query cell, that the actual value returned will be saved. In particular, if the message returns an object, then the query cell will show a string representationof the object (from toString), but it is the object itself that is saved, not the string.
Query Message (send a message to an object and optionally make assertions about the result)
parameters (3 or more, depending on the message)(1) The name of an object to receive the message
(2) The name of the message to send
(3) The query/assertion cell. If this cell is empty a query is being made and the results of sending the message will be shown here. If you put a value here you are asserting that the returned value from the message will be what you write.
(4 ...) Any parameters required by the message.
Note the difference between Message and Query Message. In Message, the query cell comes last and must be empty. In Query Message the query/assert cell comes immediately after the message name, but before any parameters. You cannot make assertions with a Method command.
| KarelFixture | |||||
| Robot | |||||
| Create | karel | 1 | 1 | North | 0 |
| Query Message | karel | move | null | ||
| Query Message | karel | anyBeepersInBeeperBag | true | ||
| Query Message | karel | anyBeepersInBeeperBag | |||
Class (change the current focus class to enable creation of objects in the new class)
parameters (1 or 2)(1) The fully qualified class name you want to use, or the abbreviation of some class you saved earlier
(2 optional) The abbreviation you want to save for this class.
(3... optional) Just as in the second row of a table, you can change the default parameter behavior in any Class command. Note that it changes the behavior for the system, not just for this class. You can give extra cells after the name cell setting the looked for parameter types to byte, short, int, and long, for integer types and to float or double for floating types. You can actually put several cells but only the last of each type will be effective.
| kareltherobot.KarelFixture | |||||
| kareltherobot.Robot | Robot | ||||
| Create | jane | 1 | 1 | North | 0 |
| Class | kareltherobot.UrRobot | ur | int | float | |
| Create | karel | 1 | 1 | North | 0 |
Here jane will be a kareltherobot.Robot and karel will be a kareltherobot.UrRobot?. We also save the name ur as an abbreviation to use in future tables or Class commands.
Note that the second row of every table is like an implicit Class command.
World (execute commands defined in the World class)
parameters (1 or more)(1) the name of the message to send to the world
(2...) any required parameters of the message.
(optional) You may place an empty cell after all the parameters. If you do so, any result of the message will be placed here (query).
(optional) If you place a query cell (empty) you may follow it with another cell with a string value (an abbreviation). The value returned from the message will be saved with this name for later use.
The Java Docs will show you what commands can be sent: http://csis.pace.edu/~bergin/KarelJava2ed/KJRdocs/. See the World class there. Some instructions cannot be executed: those that imply showing the world view. That is not supported here. You may get an exception for some of them or, more likely, it will just tell you there is no such instruction, even if there really is. The problem is that this code runs on the server, not your machine. It isn't like an applet. If the code did run on the server, there would be no one there to see it.
| KarelFixture | |||||
| ur | |||||
| World | reset | ||||
| Create | karel | 1 | 1 | East | 0 |
| World | placeBeepers | 2 | 2 | 1 | |
| World | delay | theDelay | |||
| Create | jj | theDelay | theDelay | North | 0 |
| Assert | At | jj | 1 | 1 | |
Place a beeper on second street and second avenue after clearing out everything in the world. It also shows the default delay. Finally it shows a somewhat non-sensical use of a returned value.
Static (execute static methods defined in the current class)
parameters (1 or more)(1) the name of the message to send to the current class
(2...) any required parameters of the message.
(optional) You may place an empty cell after all the parameters. If you do so, any result of the message will be placed here (query).
(optional) If you place a query cell (empty) you may follow it with another cell with a string value (an abbreviation). The value returned from the message will be saved with this name for later use.
The Java Docs will show you what commands can be sent: http://csis.pace.edu/~bergin/KarelJava2ed/KJRdocs/. See the World class there.
| KarelFixture | |||||
| kareltherobot.World | |||||
| Static | reset | ||||
| Static | placeBeepers | 2 | 2 | 1 | |
| Static | delay | theDelay | |||
| Class | kareltherobot.Robot | ||||
| Create | jj | theDelay | 1 | North | 0 |
| Assert | At | jj | 1 | 1 | |
Place a beeper on second street and second avenue after clearing out everything in the world. It also shows the current delay. Finally it shows a somewhat nonsensical use of a returned value. Note that for manipulating the World as we have done here, the World command serves just as well.
Static Field (retrieve static fields of the current class an make them available here as parameters)
parameter: the name of a field defined in the current classThe field will be retrieved and saved here with the same name.
| KarelFixture | |
| kareltherobot.Directions | |
| Static Field | North |
| Static Field | East |
| Static Field | South |
| Static Field | West |
| Static Field | infinity |
This particular set of retrievals would be redundant here, as these are done as part of the Karel Fixture itself.
Assert (make assertions from a JUnit test class -- default is KJRTest)
parameters (1 or more depending on the assertion)(1) the name of the assert method from the current tester class (default is kareltherobot.KJRTest)) without the initial assert prefix, which will be automatically added. All of these, then, begin with an upper-case letter.
(2...) any parameters required by the assertion.
If the assertion succeeds, the name cell will be shown green, if it fails, red. See the KJRTest class in the Java Docs: http://csis.pace.edu/~bergin/KarelJava2ed/KJRdocs/. You may change the assertion tester class with the Tester command.
| KarelFixture | |||||
| Robot | |||||
| World | reset | ||||
| Assert | BeepersInWorld | 0 | |||
| World | placeBeepers | 1 | 1 | 3 | |
| Assert | BeepersInWorld | 3 | |||
| Assert | BeepersInWorld | 0 | |||
| Create | karel | 1 | 1 | North | 0 |
| Assert | RobotsInWorld | 1 | |||
| Assert | RobotsAt | 1 | 1 | ||
One of the above assertions is intended to fail.
Note that you can't execute tests from these classes with this command, but only assertions.
Tester (change the class used for defining assertions)
parameters(1 or 2)(1) the name of the class used to make assertions. The default is kareltherobot.KJRTest. You may use any class that extends JUnit.TestCase?.
(2 optional) an optional name for this class for use in future Tester commands in case you need to go back and forth.
You name the class. An instance of it will be created and used by the Assert command. Note that its setUp method is NOT called. You can, however, open the class with the Class command and manipulate it with Message. Be aware that you should call setUp yourself between the test methods of the class as there is no infrastructure here to do it automatically.
| kareltherobot.KarelFixture | ||
| kareltherobot.StairClimber | ||
| Tester | kareltherobot.KJRTest | local |
This is redundant, but harmless. It simply gives a name to the class, since this is the default tester in any case.
Set KJRTest as the current tester and executer of Assert messages and give it the name local.
Note on parameters
This system works by looking at the values you put in the cells and trying to infer from them which method or constructor to use. This is a difficult process and is not perfect, since values of different types may look the same. In particular, the system can't distinguish by itself whether 42 is an int or a long or whatever. Because of this, it makes assumptions, but you are allowed to override the assumptions in two ways. The system also does not distinguish between primitive types and their wrappers, so true serves as a valid value for either a boolean or a Boolean parameter. The system automatically handles boolean, String, and other object types. The integer and floating types present a difficulty. For this reason, the system uses default values for each kind, with int and double being the original defaults. You can change these in the second row of any table and also in any Class command as described above. This is enough, provided that you don't have any methods that take, for example, both an int and a long. In those cases you can override the assumptions in a second way.Within any numeric cell, you can proceed the value you want to use with a type indicator (and a space). The valid values are
\byte
\short
\int
\long
\float
\double
So, for example, if the default is the original int and you want to send a message that requires a long argument you can say something like |Message|doIt|\long 5|
If there is a method that has name doIt and requires a long paramenter, it will be found.
In the rare situation in which you want the cell to be interpreted as a String that begins with one of our type tags, you can preceed that with \String and the rest will be interpreted as a String. \String will also force a string of digits (which looks like an int) to be interpreted as a String.
The system also assumes that things that don't otherwise parse as boolean, numeric, or known object types are Strings. Sometimes you want them to be char (or Character) instead. In this case you can preceed a single character with the \char type tag so that the system looks for a method or constructor with this type parameter. You might also want a digit to be interpreted as a character. Following \char you may put the numeric equivalent of a char, a character in apostrophes, or a string. In the latter case the first character will be used.
| kareltherobot.KarelFixture | |||||
| kareltherobot.StairClimber | sc | long | |||
| Create | karel | \int 1 | \int 1 | East | \int 0 |
| fit.Summary |
Some pages giving specifications for some robot programs. The numbering is from the exercises in the Karel++ text.
^PinSetterTask1 Problem 2 of Chapter 3.
^PickOneTuringMachine
^TestHighJumpStrategy
^ExerciseStrategyRobot
Some tests that were used during development. Many fail intentionally.
| kareltherobot.KarelFixture | |||||
| kareltherobot.Robot | Robot | int | double | ||
| Tester | local | ||||
| Class | kareltherobot.UrRobot | ur | |||
| Create | karel | 1 | 1 | North | 0 |
| Assert | At | karel | 1 | 1 | |
| Query Message | karel | anyBeepersInBeeperBag | false | ||
| Class | Robot | ||||
| Create | jane | 1 | 1 | North | 0 |
| Message | jane | anyBeepersInBeeperBag | |||
| Query Message | jane | anyBeepersInBeeperBag | false | ||
| Query Message | jane | anyBeepersInBeeperBag | |||
| Query Message | jane | anyBeepersInBeeperBag | foo | ||
| Create | jj | blah | blah | ||
| Class | foo | ||||
| kareltherobot.KarelFixture | |||||
| kareltherobot.Robot | Robot | ||||
| Assert | BeepersInWorld | 0 | |||
| Assert | BeepersInWorld | ||||
| World | placeBeepers | 1 | 1 | 3 | |
| Read World | test.kwld | ||||
| World | saveXMLWorld | foo.txt | |||
| Assert | BeepersInWorld | 2 | |||
| Assert | BeepersInWorld | 0 | |||
| Create | karel | 1 | 1 | North | 0 |
| Assert | RobotsInWorld | 1 | |||
| Assert | RobotsAt | 1 | 1 | ||
| Assert | RobotsAt | 1 | 1 | 3 | |
| Assert | blah | ||||
| Assert | BeepersInWorld | blah | |||
| Message | karel | move | |||
| Assert | FacingNorth | karel | |||
| Assert | OnStreet | karel | 2 | ||
| Assert | OnAvenue | karel | 1 | ||
| Assert | NotAt | karel | 1 | 1 | |
| Message | karel | foo | |||
| Message | foo | move | |||
| Assert | NoBeepersInBeeperBag | karel | |||
| Assert | BeepersInBeeperBag | karel | |||
| Assert | BeepersInBeeperBag | foo | |||
| Assert | Foo | karel | |||
| KarelFixture | |||||
| Robot | |||||
| Create | john | 1 | 1 | North | 1 |
| Message | john | putBeeper | |||
| Query Message | john | anyBeepersInBeeperBag | false | ||
| Query Message | john | anyBeepersInBeeperBag | true | ||
| Query Message | john | anyBeepersInBeeperBag | |||
| Query Message | john | anyBeepersInBeeperBag | foo | ||
| Query Message | john | anyBeepersInBeeperBag | |||
| Query Message | john | foo | false | ||
| Query Message | john | move | false | ||
| Message | john | putBeeper | |||
Odd tester test
| kareltherobot.KarelFixture | ||
| com.jbergin.HtmlFixtureTest | ||
| Tester | com.jbergin.HtmlFixtureTest | |
| Create | tester | Junk |
| Message | tester | setUp |
| Message | tester | testQuick |
[ User Guide] [.FrontPage] [.RecentChanges]