Sua pergunta parece dobrada para mim. Por um lado, você gostaria de comparar duas estruturas de teste, por outro lado, gostaria de implementar testes facilmente, ter afirmações naturais, etc ...
Ok, em primeiro lugar, o JUnit está tentando recuperar o atraso com o TestNG em termos de funcionalidade, eles preenchem a lacuna em alguns aspectos com a v4, mas não na minha opinião. Coisas como anotações e provedores de dados ainda são muito melhores no TestNG. Também são mais flexíveis em termos de execução de teste, pois o TestNG possui dependência, agrupamento e ordenação de teste.
O JUnit ainda exige que certos métodos antes / depois sejam estáticos, o que limita o que você pode fazer antes da execução dos testes, o TestNG nunca tem esse problema.
TBH, principalmente as diferenças entre as duas estruturas não significam muito, a menos que você se concentre nos testes de integração / automação. A partir da minha experiência, a JUnit foi criada desde o início para testes de unidade e agora está sendo levada a níveis mais altos de testes, o que a IMO a torna a ferramenta errada para o trabalho. O TestNG se sai bem em testes de unidade e, devido ao seu robusto fornecimento de dados e excelentes habilidades de execução de testes, funciona ainda melhor no nível de integração / automação.
Agora, para o que acredito ser uma questão separada, como escrever testes bem estruturados, legíveis e de manutenção. Tenho certeza de que você sabe muito sobre isso, mas coisas como Padrão de Fábrica , Padrão de Comando e PageObjects (se os sites de teste) são vitais, é muito importante ter uma camada de abstração entre o que o teste (SUT) e o teste real é (asserções da lógica de negócios). Para ter afirmações muito mais agradáveis, você pode usar o Hamcrest . Faça uso da herança / interfaces de javas para reduzir a repetição e reforçar a semelhança.
Quase esqueci, também use o Test Data Builder Pattern , que, juntamente com a anotação do provedor de dados do TestNG, é muito útil.