I'm just starting to learn SystemVerilog and work with FPGAs, and so far I haven't found a satisfactory way to test my code. I'm coming from a software background, and I have always been writing thorough automated tests for my code. I have been using JUnit-style frameworks (with lots of domain-specific wrapping on top, to reduce boilerplate), as well as QuickCheck-style frameworks, and found ways to use these frameworks to write concise test code that nevertheless provides me with high confidence in the product I'm developing. I haven't yet found anything equivalent for hardware description languages.
Introductory Verilog texts typically present testbenches that are just driving the input signals. These testbenches are unreadable repetitive walls of code (signal assignments) without assertions; these tests are not even automatic. Some texts try to incorporate machine-checkable assertions into the testbench code so that one does not have to look at waveforms to determine whether the test passed or failed. Still, the "wall of repetitive text" problem remains.
I researched the issue further, and found that the current industry standard for RTL verification is UVM. The idea does look better to me, I haven't looked in detail into it, but for me the big disadvantage of UVM is that UVM testbenches are not synthesizable.
If I can't run my tests on the actual FPGA, how can I be confident that my synthesized design works correctly? I understand that there is a high chance that it will work after the simulation tests have passed, but there are a lot of assumptions involved (that my code is not racy, that my code meets timing requirements, that the synthesis tool is correct etc.)
A parallel in the software world would be developing a program in C, compiling with gcc and testing it on x86 on Windows, and then compiling it with Clang and running it in production on ARM on Linux. The program should work, assuming that it does not have undefined behavior, does not have non-portable assumptions about the execution environment, both compilers don't have bugs affecting the program. This is a lot of assumptions that most software engineers would not make and instead would just run their tests on the production configuration.
Am I fundamentally misunderstanding something about real-world hardware design process? How are designs verified once synthesized into FPGAs and actual silicon? How to run existing test cases on designs in FPGAs and silicon?
Are there any industry-standard practices for synthesizable testbenches? Do people actually write synthesizable testbenches?