2012-02-22 13 views
6

Sto provando a eseguire un test della GUI unitamente a DUnit a un'applicazione la cui forma principale crea dinamicamente fotogrammi su se stessa. Sono stato in grado di creare la maschera principale dell'applicazione-test come modulo nel caso di test e accedere alle sue voci di menu ecc.Test DUnit GUI: Posso forzare "Applicazione" su un "modulo" diverso?

Il problema si presenta quando l'applicazione tenta di creare un frame in modo dinamico. La lettura delle risorse del frame arriva al punto in cui è necessario l'handle della finestra (nel mio caso, l'impostazione della didascalia di un foglio di tabulazione). Qui va da TWinControl.GetHandle a TWinControl.CreateWnd e a TCustomFrame.CreateParams.

In questo CreateParams, il codice dice:

if Parent = nil then 
    Params.WndParent := Application.Handle; 

Questo è dove si verifica la differenza. Quando eseguo l'applicazione effettiva (non nel test), Application.Handle restituisce un numero diverso da zero e il flusso continua ok. Ma nella applicazione di test dunit, l'Application.Handle qui restituisce 0. Questo fa sì che il codice nella TWinControl.CreateWnd di sollevare un'eccezione dicendo che il telaio non ha un genitore:

with Params do 
    begin 
    if (WndParent = 0) and (Style and WS_CHILD <> 0) then 
     if (Owner <> nil) and (csReading in Owner.ComponentState) and 
     (Owner is TWinControl) then 
     WndParent := TWinControl(Owner).Handle 
     else 
     raise EInvalidOperation.CreateFmt(SParentRequired, [Name]); 

mi piacerebbe cercare di aggirare questo problema (e in generale, tutti i problemi di test) senza modificare il codice di "produzione" solo a causa dei test. Potete fornire qualche indizio sul fatto che potrei in qualche modo forzare la "Applicazione" a qualcos'altro, o in qualche altro modo aggirare questo?

Guardando il codice, un possibile altro scenario alternativo potrebbe essere quello di provare ad ottenere il proprietario (che è il mio "MainForm" dell'applicazione da testare, cioè di chi manterrà il destinatario) in csStatando lo stato durante la creazione di questo frame nel test, ma almeno inizialmente non sembra così semplice far sì che ciò accada.

+0

Il tuo dpr ha un'applicazione. Inizializza? Forse questo imposta la maniglia. – mjn

+0

Sia la mia app di test che l'effettiva applicazione hanno Application.Initialize nel loro dprs. Posso provare a scorrere le inizializzazioni per vedere se riesco a trovare un posto dove Application.Handle è impostato su qualcosa o meno. – DelphiUser

+0

DUnit non mi sembra il migliore anche per testare una GUI. – GolezTrol

risposta

0

Grazie per tutti i commenti e le risposte! Credo di aver risolto i problemi, almeno quelli scoperti finora. Riassumo le mie scoperte e la situazione finale di seguito (nel caso in cui qualcun altro lo trovasse utile).

Ho una classe decoratore di test che eredita da TTestSetup, che contiene un riferimento a un form fittizio (principale) che crea quando necessario.

Ho anche trovato un modo per commutare l'Application.MainForm in esecuzione usando approccio di questo: http://www.swissdelphicenter.ch/torry/showcode.php?id=665

Nel metodo di prova decoratore SetUp Creo prima forma fittizia e quindi impostarla come forma principale dell'applicazione (questa impostazione potrebbe non essere necessaria qui).

Quindi ho una classe case test (che eredita da TGUITestCase), i cui setUp e TearDown vengono eseguiti per ogni test. In questo SetUp creo il mainform che sto testando e quindi lo metto come il modulo principale dell'applicazione. Quindi, dopo il test nel TearDown del caso di test, ho impostato nuovamente il form fittizio come forma principale dell'applicazione, e solo dopo questa chiamata Close e Free alla mainform che sto testando. Altrimenti, liberando un modulo che è attualmente Application.MainForm causerebbe la chiusura dell'intera applicazione DUnit.

+0

Mentre questo funziona per te, è ancora un uso improprio di TFrames. –

2

Invece di aggirare un modo per impostare Application.Handle, è necessario creare un TForm e impostare il proprio frame.parent come TForm.

//Dunit Test Scaffolding code...Set up a workable environment for the test: 
aForm := TForm.Create(nil); 
aFrame := TFrame.Create(aForm); 
aFrame.Parent := aForm; 

In applicazioni reali, telai avranno un genitore (essere imparentato ad una finestra, un TForm o TPanel di solito). Stai provando a dire a un frame di funzionare senza un genitore, che TFrame non è progettato per fare.

+0

In realtà, non sto cercando di dire a un frame di girare senza un genitore, basta crearlo. Nella mia vera applicazione i frame sono creati prima con la mainform come Owner. Successivamente, quando vengono effettuate determinate selezioni, viene scelto un frame adatto in base alla selezione e questo frame viene quindi impostato in modo da avere il padre come pannello nel modulo principale. Pertanto, tutti i fotogrammi verranno visualizzati con lo stesso genitore, uno alla volta, ma creati in anticipo. Tutto questo accade nel mio codice di produzione, che non voglio cambiare solo per motivi di test. – DelphiUser

+0

Non penso che TFrame sia progettato per consentire questa cosa che stai facendo. Dovresti semplicemente creare e ancorare un modulo senza un bordo e non avrai questi problemi. C'è ZERO BENEFIT nel creare una cornice nel tuo caso. –

+0

Quando utilizzo i frame, non devo considerare alcun problema di docking, quindi c'è un vantaggio diverso da zero, almeno per me. – DelphiUser