In addition to Greg's answer there are some other things that you can do with your code once you get it running on the VM.
From what I understand the Pi's GPIO are memory mapped devices, thus you can write an out of band process that monitors the Output bits and reports their values so you can track how the hardware is being driven. (Note that you need to verify that the responses you see match the actual hardware - EG set up some simple test cases)
Once you can monitor the outputs then you can feed them into a hardware simulation that estimates the physical location of the vehicle. This can be as simple or complicated as you want. The aim is not to be perfect but to give feedback to the user that when you run the forward() command for 10 seconds, the vehicle moves 10 times further than if you ran it for 1 second. You also accumulate distance with simple time based integrations to change the vehicles location.
The final step is then to add on to your simulation and feed simulated sensor data back into GPIO inputs based on where the vehicle is in the simulated world, and show how your actual vehicle code responds. EG when a sensor detects a simulated cliff in front of the vehicle, your actual vehicle code should be seen to stop the forward motion.
The goal is not to produce a perfect real world simulation of you vehicle, but to act as a tool to help you verify that you consume inputs and generate outputs in a manner that seem reasonable - IE showing that you have dotted your I's and crossed your T's in your code. Thus you should aim for the simplest and dumbest simulation that achieves that goal and avoid the temptation to make your hardware simulation perfect.