There is several way indeed. Some use Proteus, some MPLAB sim, some use Serial communication (and/or ICD like Pickit 2 or MicroCode ICD), or still some LEDs or a LCD.

What's the best method? Hard to tell, for me a blend mix of everything above (less Proteus as I don't trust it) do a really good job. And then, it really depend where I am in the development stage and how big the "bug" is.

An ICD tells you exactly what happen in your code in real life, and more, it give you ALL internal register status, down side, they're usually a bit slow.

HTH