2011-01-20 45 views
1

我是單元測試新手。我不知道是否值得對以下代碼進行單元測試。這裏是用德爾福編寫的示例方法:下面的代碼是否值得單元測試?

function TCoreAudio.CreateAudioClient: IAudioClient; 
var 
    MMDeviceEnumerator: IMMDeviceEnumerator; 
    MMDevice: IMMDevice; 
    MixFormat: PWaveFormatEx; 
    AudioClient: IAudioClient; 
    HR: HResult; 
begin 
    Result := nil; 

    if CheckWin32Version(6, 0) then // The Core Audio APIs were introduced in Windows Vista. 
    begin 
    HR := GetInstance().CoCreateInstance(CLSID_MMDeviceEnumerator, nil, CLSCTX_ALL, 
     IMMDeviceEnumerator, MMDeviceEnumerator); 
    if Failed(HR) then 
     Exit; 
    HR := MMDeviceEnumerator.GetDefaultAudioEndpoint(eRender, eConsole, MMDevice); 
    if Failed(HR) then 
     Exit; 
    HR := MMDevice.Activate(IAudioClient, CLSCTX_ALL, nil, AudioClient); 
    if Failed(HR) then 
     Exit; 
    HR := AudioClient.GetMixFormat(MixFormat); 
    if Failed(HR) then 
     Exit; 
    HR := AudioClient.Initialize(AUDCLNT_SHAREMODE_SHARED, 0, 0, 0, MixFormat, nil); 
    CoTaskMemFree(MixFormat); 
    if Failed(HR) then 
     Exit; 

    Result := AudioClient; 
    end; 
end; 

該方法是否值得單元測試?如果是,需要測試哪些部分?

謝謝。

回答

3

單元測試通常是自下而上的方法。所以你會開始單元測試在你的函數中使用的類。在確認所有這些類都被單元測試覆蓋之後,您可以爲您的函數CreateAudioClient創建一個單元測試。此功能的單元測試可能是很容易的,這樣的事情:

AudioClient := CreateAudioClient; 
CheckNotNil (AudioClient); 

注意,通常單元測試類的接口,而不是一個函數或過程的主體。

希望有所幫助。

如果它是值得的問題,取決於多種因素:

  • 有多容易建立一個單元測試呢?它會是多少努力?
  • 這部分有多重要?根據這部分的重要性,答案可能總是「是的,這絕對值得單元測試」 - 或者不。
  • 它有多大可能改變?如果您認爲這種方法可能在未來的某個地方發生變化,那麼添加單元測試可避免以後引入錯誤。
+0

但是您提出的示例單元測試(AudioClient:= CreateAudioClient; CheckNotNil(AudioClient);)將在運行Windows XP計算機時失敗,並且如果您在Windows Vista及更高版本上運行則會失敗。 – CodeSnake 2011-01-20 14:32:20

+0

@CodeSnake這是你需要寫入測試的東西。 – 2011-01-20 15:51:30

0

這真的取決於你多長時間相信這種方法會發生變化......如果你已經有一些測試它的單位,那麼是的,否則這是真的取決於你,但我是不確定從整個單元測試這個方法是個好主意,因爲它調用了其他單元的其他方法。底線,它取決於你如何選擇這樣做,最好的方法是將測試添加到整個項目中,否則我不能在「部分測試」中看到任何值。

6

您面臨的問題是如何測試它,而不是測試它。

這是許多COM調用的包裝,可能由於許多不同的原因而失敗。這些可能的COM故障條件是測試此例程最重要的方面。但是你不能輕易地引發COM例程失敗。爲了測試這些COM失敗模式,你需要使用一個模擬,這是一個很大的飛躍。

3

當單元測試作爲應用程序和第三方API(甚至是系統API)之間的接口的類時,您想測試該類調用並正確響應API。如果沒有某種方式來檢測傳遞給API的內容並返回適當的響應,則無法做到這一點。

在您的情況下,您正在進行一系列調用以獲取IAudioClient。我會說你做得太多了。在一個函數中有一個以上的條件是一個條件太多(我想我只是把自己弄糊塗了)。我會把它分成幾個功能,你可以單獨測試。

function TCoreAudio.CreateAudioClient: IAudioClient; 
var 
    MMDeviceEnumerator: IMMDeviceEnumerator; 
    MMDevice: IMMDevice; 
    MixFormat: PWaveFormatEx; 
    AudioClient: IAudioClient; 
begin 
    Result := nil; 
    if IsVista then 
    try 
     MMDeviceEnumerator := GetMMDeviceEumerator; 
     MMDevice := GetMMDevice(MMDeviceEnumerator); 
     AudioClient := GetAudioClient(MMDevice); 
     MixFormat := GetMixFormat(AudioClient); 
     InitializeAudioClient(AudioClient, MixFormat); 
     Result := AudioClient; 
    except 
     //Handle exception 
    end; 
end; 

function TCoreAudio.IsVista: boolean; 
begin 
    Result := CheckWin32Version(6, 0); 
end; 

function TCoreAudio.GetMMDeviceEnumerator: IMMDeviceEnumerator; 
begin 
    HR := GetInstance().CoCreateInstance(CLSID_MMDeviceEnumerator, nil, CLSCTX_ALL, 
     IMMDeviceEnumerator, Result); 
    if Failed(HR) then 
     raise Exception.Create('Failed to create device enumerator'); 
end; 

function TCoreAudio.GetMMDevice(ADeviceEnumerator: IMMDeviceEnumerator): IMMDevice; 
begin 
    HR := MMDeviceEnumerator.GetDefaultAudioEndpoint(eRender, eConsole, Result); 
    if Failed(HR) then 
     raise Exception.Create('Failed to retrieve device'); 
end; 

function TCoreAudio.GetAudioClient(ADevice: IMMDevice): IAudioClient; 
begin 
    HR := MMDevice.Activate(IAudioClient, CLSCTX_ALL, nil, Result); 
    if Failed(HR) then 
     raise Exception.Create('Failed to retrieve audio client'); 
end; 

function TCoreAudio.GetMixFormat(AAudioClient: IAudioClient): PWaveFormatEx 
begin 
    HR := AudioClient.GetMixFormat(Result); 
    if Failed(HR) then 
     raise Exception.Create('Failed to retrieve mix format'); 
end; 

procedure TCoreAudio.InitializeAudioClient(AAudioClient: IAudioClient, AMixFormat: PWaveFormatEx); 
begin 
    HR := AudioClient.Initialize(AUDCLNT_SHAREMODE_SHARED, 0, 0, 0, AMixFormat, nil); 
    CoTaskMemFree(MixFormat); 
    if Failed(HR) then 
     raise Exception.Create('Audio client failed to initialize'); 
end; 

現在你可以提供一個模擬/假/存根各項功能,確保API被調用合適的參數,並迫使故障情況,以確保您的生產代碼是妥善處理它們。

您不需要問產品代碼是否應該測試。答案總是肯定的。 (警告:無恥的自我推銷)我最近寫了關於我blog。有時候,即使是所有陳述中最無害的一點,即賦值語句,也無法按預期工作。

事實上,現在它已經分解成它看起來像一個新的創建類,只是渴望爆發。