2015-09-07 76 views
2

如果嘗試將一些基本單元測試添加到大量現有(Fortran 90)代碼中,那麼這將是一種明智的方法,該代碼僅在鎖定環境中進行開發,這個系統沒有機會安裝任何第三方框架。我幾乎侷限於標準的Linux工具。目前代碼庫使用非常有限的一套測試在完整的系統級別進行測試,但這非常耗時(需要多天的運行時間),因此在開發過程中很少使用在鎖定環境中對Fortran進行基本單元測試

理想地期望能夠逐步向關鍵系統添加目標測試,而不是一次嘗試完全徹底檢查整個代碼庫。

服用例如模塊的下方,並假設斷言型宏的實現如在Assert in Fortran

MODULE foo 
    CONTAINS 
    FUNCTION bar() RESULT (some_output) 
     INTEGER :: some_output 
     some_output = 0 
    END FUNCTION bar 
END MODULE foo 

幾個可能的方法彈簧的腦海中詳述,但有可能是技術或admistrative挑戰implementating這些其中我不知道:

每個模塊
  1. 單獨的測試模塊,如以下,並且具有單一的主測試運行來調用每個模塊內的每個功能

    MODULE foo_test 
        CONTAINS 
        SUBROUTINE bar_test() 
        ! .... 
        END SUBROUTINE bar_test() 
    END MODULE foo_test 
    
  2. 上述類似的方法,但與每個測試單獨的可執行文件。顯而易見的好處是,單一故障不會終止所有測試,但可能難以管理大量測試可執行文件,並且可能需要大量額外的代碼。

  3. 使用預處理器在每個模塊中包含包含測試的主函數,例如,在gfortran Fortran 90 with C/C++ style macro (e.g. # define SUBNAME(x) s ## x)中,並使用構建腳本自動測試存儲在主代碼文件中預處理器分隔符之間的main。

我已經使用一些現有的Fortran框架的嘗試(如記錄在>Why the unit test frameworks in Fortran rely on Ruby instead of Fortran itself?>),但對於這個特定的項目,不存在能夠我使用的系統上安裝額外的工具的可能性。

回答

2

在我看來,斷言機制並不是Fortran單元測試的主要關注點。正如您在鏈接中回答的那樣,Fortran有幾個單元測試框架,例如funit和FRUIT。

不過,我認爲,主要問題是依賴關係的解決。您可能擁有一個包含許多相互依存模塊的巨大項目,並且您的測試應該涵蓋使用其他模塊的其中一個模塊。因此,您需要找到這些依賴關係並相應地構建單元測試。一切都歸結爲編譯可執行文件,斷言的優勢非常有限,因爲您無論如何都需要定義您的測試並自行進行比較。

我們正在用Waf構建我們的Fortran應用程序,它帶有一個單元testing utility itself。現在,我不知道這是否可以讓你使用,但唯一的要求是Python,它幾乎可以在任何平臺上使用。一個缺點是,測試依賴於返回代碼,而這並不容易從Fortran獲得,至少在Fortran 2008之前不能以便攜方式獲得,而Fortran 2008建議在返回代碼中提供停止代碼。所以我修改了我們項目成功的檢查。而不是檢查返回代碼,我希望測試寫一些字符串,並在輸出中檢查的是:

def summary(bld): 
      """ 
      Get the test results from last line of output:: 

        Fortran applications can not return arbitrary return codes in 
        a standarized way, instead we use the last line of output to 
        decide the outcome of a test: It has to state "PASSED" to count 
        as a successful test. 

        Otherwise it is considered as a failed test. Non-Zero return codes 
        that might still happen are also considered as failures. 

        Display an execution summary: 

        def build(bld): 
          bld(features='cxx cxxprogram test', source='main.c', target='app') 
          from waflib.extras import utest_results 
          bld.add_post_fun(utest_results.summary) 
      """ 
      from waflib import Logs 
      import sys 

      lst = getattr(bld, 'utest_results', []) 

      # Check for the PASSED keyword in the last line of stdout, to 
      # decide on the actual success/failure of the test. 
      nlst = [] 
      for (f, code, out, err) in lst: 
        ncode = code 
        if not code: 
          if sys.version_info[0] > 2: 
            lines = out.decode('ascii').splitlines() 
          else: 
            lines = out.splitlines() 
          if lines: 
            ncode = lines[-1].strip() != 'PASSED' 
          else: 
            ncode = True 
        nlst.append([f, ncode, out, err]) 
      lst = nlst 

此外,我按照約定增加測試中,只是一個目錄,必須提供構建腳本和與_test.f90結束該目錄中的所有文件都會被假定爲單元測試,我們將嘗試建立並運行它們:

def utests(bld, use, path='utests'): 
    """ 
    Define the unit tests from the programs found in the utests directory. 
    """ 
    from waflib import Options 
    for utest in bld.path.ant_glob(path + '/*_test.f90'): 
      nprocs = search_procs_in_file(utest.abspath()) 
      if int(nprocs) > 0: 
        bld(
         features = 'fc fcprogram test', 
         source = utest, 
         use = use, 
         ut_exec = [Options.options.mpicmd, '-n', nprocs, 
            utest.change_ext('').abspath()], 
         target = utest.change_ext('')) 
      else: 
        bld(
         features = 'fc fcprogram test', 
         source = utest, 
         use = use, 
         target = utest.change_ext('')) 

你可以找到像在Aotus library定義的單元測試。

from waflib.extras import utest_results 
utest_results.utests(bld, 'aotus') 

它是那麼還可以通過在夜猴運行

./waf build --target=aot_table_test 

建立從單元測試僅子集,例如:其通過利用在wscript。我們的測試環境有點微薄,但我認爲這個基礎設施展會實際上相當不錯。測試可以簡單地利用項目中的所有模塊,並且可以毫不費力地進行編譯。

現在我不知道這是否適合你,但我會考慮更多關於你的測試在你的構建環境中的整合,而不是關於斷言的東西。在每個模塊中都有一個測試程序是一個好主意,然後可以從測試程序中輕鬆調用。我會試着針對你想測試的每個模塊尋找一個可執行文件,其中每個模塊當然可以包含多個測試。

+0

感謝您的反饋意見。不幸的是Waf在這裏不是一個選項(令人沮喪的是,我沒有辦法從外部源代碼導入代碼,而不是依賴性問題)。我完全同意你關於解耦和依賴解決方案是主要挑戰的觀點 - 我尋找解決方案的原因之一是鼓勵團隊的其他成員考慮依賴關係問題;我發現在過去,單元測試是鼓勵這種做法的有效方法。看到你如何在一個並行項目上解決問題非常有趣。歡呼聲 – s8129

+1

至少,Fortran 2008標準建議編譯器供應商在停止語句(例如停止2)中使用錯誤代碼作爲退出代碼,因此有一種準便攜式方式返回退出代碼。 –

+0

@BálintAradi,感謝您指出,我不依賴於F2008的功能,而且上次我用不同的編譯器進行了檢查,結果無法正常工作。我會將其添加到答案中。 – haraldkl