[英]Unit testing a compiler
什么被認為是對復雜單元(如編譯器)進行單元測試的最佳方法?
多年來我寫了一些編譯器和解釋器,我發現這種代碼很難以一種好的方式進行測試。
如果我們采用類似抽象語法樹生成的東西。 你會如何使用TDD測試?
小結構可能很容易測試。 例如:
string code = @"public class Foo {}";
AST ast = compiler.Parse(code);
因為那不會產生很多ast節點。
但是,如果我真的想測試編譯器可以為類似方法生成AST:
[TestMethod]
public void Can_parse_integer_instance_method_in_class ()
{
string code = @"public class Foo { public int method(){ return 0;}}";
AST ast = compiler.Parse(code);
你會斷言什么? 手動定義代表給定代碼的AST,並斷言生成的AST符合手動定義的AST看起來非常簡潔,甚至可能容易出錯。
那么像這樣的TDD復雜場景的最佳策略是什么?
首先,如果您測試編譯器,則無法獲得足夠的測試! 用戶真的依賴於編譯器生成的輸出,就像它始終是黃金標准一樣,所以真的要注意質量。 所以,如果可以的話,測試你可以提出的每一個測試!
其次,使用所有可用的測試方法,並在適當的地方使用它們。 實際上,您可以在數學上證明某種轉變是正確的。 如果你能夠這樣做,你應該這樣做。
但是我看到的每個內部編譯器都涉及啟發式和許多優化的,手工制作的代碼在其內部; 因此,輔助證明方法通常不再適用。 在這里,測試到位,我的意思是很多!
在收集測試時,請考慮不同的情況:
現在,這聽起來像是一項非常多的工作! 是的確如此,但有幫助:世界上有幾個用於(C-)編譯器的商業測試套件以及可能幫助您應用它們的專家。 這里有一小部分我知道的人:
首先,解析通常是編譯器項目的一個微不足道的部分。 根據我的經驗,它不會占用超過10%的時間(除非我們在談論C ++,但如果你正在設計它,你就不會在這里提問)所以你寧願不把大部分時間投入到解析器測試中。
盡管如此,TDD(或者你稱之為)還是在開發中端的過程中,你經常需要驗證,例如你剛剛添加的優化確實導致了預期的代碼轉換。 根據我的經驗,這樣的測試通常是通過給編譯器特制的測試程序和grepping輸出程序集來實現預期的模式(這個循環展開了四次嗎?我們設法避免內存寫入是這個函數嗎?等等)。 Grepping程序集不如分析結構化表示(S-exprs或XML),但它很便宜並且在大多數情況下都能正常工作。 盡管你的編譯器在增長,但是非常難以支持。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.