Это действительно зависит от того, какие части компилятора вы пишете. Было бы хорошо, если бы вы могли сохранять отдельные фазы, чтобы помочь изолировать проблемы, но на любом этапе и даже на уровне интеграции вполне разумно иметь модульные тесты, состоящие из пар исходного кода и скомпилированного вручную кода. Вы можете начать с самых простых легальных программ и убедиться, что ваш компилятор выводит то же самое, что и при компиляции вручную.
Поскольку сложность возрастает, а ручная компиляция становится громоздкой, для компилятора полезно вести некоторый журнал того, что он сделал. Затем вы можете обратиться к этому журналу, чтобы определить, были ли запущены определенные преобразования или оптимизации для данной исходной программы.
В зависимости от вашего языка, вы можете рассмотреть генератор случайных программ из коллекции фрагментов программы (в духе QuickCheck). Этот генератор может проверить стабильность вашего компилятора и способность обрабатывать потенциально непредвиденные входные данные.