Assignment #3: Mars Rover¶
This task puts your unit testing, modules making, and exception handling knowledge to use by writing tests and classes for the Mars rover named Curiosity.
Selfie of Curiosity on Mars.¶
You will create a simulation for issuing commands to Curiosity. The idea is to create a command at mission control, convert that command into a message send it to the rover, then have the rover respond to that message.
We will provide descriptions of the required features you need to implement in three separate classes:
Command: A type of object containing aCommandTypefield.CommandTypeis one of the given strings in the table below. SomeCommandTypesare coupled with aNewPositionproperty and some are coupled with aNewModeproperty. EveryCommandobject is a single instruction to be delivered to the rover.Message: AMessageobject has aNamefield and can contain severalCommandobjects.Messageis responsible for bundling the commands from mission control and delivering them to the rover.Rover: An object representing Curiosity, the mars rover. This class contains information on the rover’sPosition, operatingMode, andGeneratorWatts. It will also contain a method that you will write,ReceiveMessage. This method will include conditional statements for each type of command the rover receives and updates the rover’s properties.
In true TDD form, you will be asked to first write the appropriate units tests for these features, then write the code in the given class to pass those tests.
Getting Started¶
Fork the Mars rover starter code.
Write a unit test for each test item listed below.
Note
Two
Commandobject tests have been created for you as examples.Use test-driven development (TDD) to create each of the classes described below.
You are responsible for creating the
Rover.ReceiveMessage()method.
How-To TDD¶
Recall that in TDD, you write the test for a given behavior before you code the actual function. Feel free to review the Test/Code cycle while you work on this project.
Focus on one test at a time.
Write the test and then create the code to make it pass.
Only write the minimum amount of code needed to make the test pass.
There are some constraints on how you can implement these features. A description of each class is below.
Each numbered item describes a test. You should use the given phrases as the test method names when creating your tests.
You must create 13 tests (14, if you do the bonus) for this assignment.
Warning
Did you catch the part about only working on ONE test at a time? Do NOT try to write all of the tests at once. Doing so will be inefficient and will cause excessive frustration.
A. Command¶
Command Class¶
We’ll follow TDD practices for the creation of Message and Rover, but for
this class, Command, we’ve provided the functionality. Command is already
written for you and you do not need to modify it to write passing tests. Open up and
examine the file Command.cs.
This class builds an object with three fields:
CommandType,NewPosition, andNewMode.CommandTypeis a string that represents the type of command. A command type will be one of the following:'MODE_CHANGE'or'MOVE'.To peek ahead at the full functionality of these types, refer to Command Types table.
NewPositionis anintvalue provided in conjunction with a “MOVE” command type.NewModeis astringvalue provided in conjunction with a “MODE_CHANGE” command type.
Example
Command ModeCommand = new Command("MODE_CHANGE", "LOW_POWER");
Command MoveCommand = new Command("MOVE", 12000);
'MODE_CHANGE' and 'MOVE' are passed in and set the CommandType value
by all constructors.
'LOW_POWER' and 12000 are passed in as value. Different command
types require different kinds of values and there are two different constructors to
handle each command type and its corresponding value.
Don’t worry about the mode options for now. To peek ahead, see Rover Modes table.
Now that we’ve gone over the class, let’s check out the tests.
Command Tests¶
To begin, open and examine MarsRoverTests/CommandTests.cs. Two tests have been created for
you. When a user creates a new Command object from the class, we want to make
sure they pass a command type as the first argument.
Test 1¶
Note that the test name reads, “ArgumentNullExceptionThrownIfCommandTypeIsNullOrEmpty”.
Look at the constructors in
Command.cs. In each, a null or emptycommandTypeargument results in an exception thrown.Use the “Tests” tab in Visual Studio to run the Command unit tests. Verify that the tests pass.
Next, change the first assertion in
CommandTests.csto expectmessage: 'Oops'. Run the tests again to verify that the test fails (the error message did not match"Command type required.").Restore the
Assertmethod’s expected argument to be"Command type required.".
Test 2¶
Look at the second Command test called “ConstructorSetsCommandType”.
This test checks that the constructor in the Command
class correctly sets the CommandType property in the new object.
Without editing,
Command.cscontains the correct code. Click “Run” to verify that the first and second tests both pass.You do not need to catch an exception in this test.
You may not need to know the specific types of commands to write this test. In fact, you can change the
commandTypeinput to any string value and run the test. Does it still pass?
Test 3¶
Look at the third test. “ConstructorSetsInitialNewPositionValue” is the
method name. This test checks that the constructor
correctly sets the NewPosition field in the new Command object.
You may not need to know a proper
NewPositionvalue in order to write this test.
Run the tests to verify that all 3 command tests pass.
Test 4¶
Write a fourth Command class test. This should be called “ConstructorSetsInitialNewModeValue”.
This test is responsible for checking that the third field on the Command class, NewMode
is set by a Command constructor.
Write the test to check that a
Commandconstructor that is passed a second string value will set that string value toNewMode.Run the test suite. This new test will initially fail.
Add an additional constructor to
Commandthat sets theNewModefield when passed a string value.Re-run the tests. Your new test should pass now.
Note
As you move through the remaining instructions, the amount of guidance will decrease. Refer to your earlier, passing tests to help you construct new tests and passing code.
B. Message¶
Recall, the role of a message object is to bundle commands to send to the rover.
Message Class¶
This class builds an object with two properties.
Message(string name, Command[] commands)Nameis a string that is the name of the message.Commandsis an array ofCommandobjects.
Example
Command[] commands = {new Command("MODE_CHANGE", "LOW_POWER"), new Command("MOVE", 500)};
Message newMessage = new Message("Test message with two commands", commands);
Message Tests¶
At the same level as CommandTests, open the test file MessageTests and
write the unit tests for the Message class as described below.
Tip
Inside this test file, you will have to create at least one commands
array, fill it with some Command objects, and pass it into the Message
constructors you are testing.
Test 5¶
This unit test has been started for you. The title, “ArgumentNullExceptionThrownIfNameNotPassedToConstructor”
indicates that it will look similar to the first test in the CommandTests file.
Review the first test in CommandTests for an example of how to write this test.
When you run the tests, the test will likely fail because you have not written the class to include this feature.
Look at the code in
Command. Use that to help you write theMessageclass inMessage.csso that your test passes. Refer to the Message Class description above for more details.
Test 6¶
Use “ConstructorSetsName” as the test name. The test confirms
that the constructor in the Message class correctly sets the
Name property in a new message object.
Test 7¶
Use “ConstructorSetsCommandsField” as the method name.
This test confirms that the Commands property of a new message object
contains the data passed in from the Message(name, commands) call.
Warning
You are moving onto the red planet now. Be prepared for fewer instructions.
C. Rover¶
Rover receives a message object, updates its properties from the message, and
returns the results.
Rover Class¶
This class builds a rover object with a few properties. It will also contain
a method called ReceiveMessage to handle updates to its properties.
public Rover(int position)positionis a number representing the rover’s position.Sets
PositiontopositionSets
Modeto'NORMAL'Sets default value for
generatorWattsto 110
public void ReceiveMessage(Message message)messageis aMessageobjectThis method does not return anything
It applies the contents of the
Messagesent to update certain properties of the rover objectDetails about how to respond to different commands are in the Command Types table.
Example
Command[] commands = {new Command("MOVE", 5000)};
Message newMessage = new Message("Test message with one command", commands);
Rover newRover = new Rover(98382); // Passes 98382 as the rover's position.
Console.WriteLine(newRover.ToString());
newRover.ReceiveMessage(newMessage);
Console.WriteLine(newRover.ToString());
Output
Position: 98382 - Mode: NORMAL - GeneratorWatts: 110
Position: 5000 - Mode: NORMAL - GeneratorWatts: 110
Rover Tests¶
Open RoverTests.cs and write the following tests. Write the code to
make them pass in Rover.cs. Remember to use the given phrase as the test
method name.
Test 8¶
“ConstructorSetsDefaultPosition”. Refer to the Rover Class description above for the default value.
Test 9¶
“ConstructorSetsDefaultMode”.
Test 10¶
“ConstructorSetsDefaultGeneratorWatts”.
Test 11¶
“RespondsCorrectlyToModeChangeCommand”.
The test should check that when a rover object receives a message that contains a “MODE_CHANGE” command, that rover’s
Modefield is updated.The rover has two modes that can be passed as values to a mode change command, “LOW_POWER” and “NORMAL”.
Test 12¶
“DoesNotMoveInLowPower”.
The test confirms that the rover position does not change when sent a “MOVE” command in “LOW_POWER” mode.
Use the Rover Modes table for guidance on how to handle move commands in different modes.
Test 13¶
“PositionChangesFromMoveCommand”.
A
MOVEcommand will update the rover’s position with the position value in the command.
Rover Command Types¶
Command |
Value sent with command |
Updates to |
|---|---|---|
MOVE |
Number representing the position the rover should move to. |
|
MODE_CHANGE |
String representing rover mode (see modes) |
|
Note
The rover does not move while in “LOW_POWER” mode.
Rover Modes¶
Mode |
Restrictions |
|---|---|
LOW_POWER |
Can’t be moved in this state. |
NORMAL |
None |
Bonus Mission¶
Add the following test that checks for unknown commands in
RoverTests.cs.
Test 14¶
“RoverReturnsAMessageForAnUnknownCommand”.
Submitting Your Work¶
In Canvas, open the Mars Rover assignment and click the “Submit” button. An input box will appear.
Copy the URL for your repl.it project and paste it into the box, then click “Submit” again.
