Il mio caso motivante è l'automazione del test hardware. Abbiamo diversi tester (banchi di apparecchiature da laboratorio che si collegano al "dispositivo in prova" (DUT)) e scriviamo i file di configurazione di test che istruiscono il tester su quali serie di test eseguire. I test eseguiti prendono anche i parametri dalla configurazione.
Al momento l'accoppiamento tra questi è più alto di quanto mi piacerebbe, quindi sto cercando di trovare un buon modello per mantenere la logica per come eseguiamo i test (oggetto "tester") separatamente da quali test vogliamo eseguire in ogni esecuzione particolare (gli oggetti di configurazione).
Il meglio che ho trovato finora è il seguente (sintassi non verificata, ma solo un'idea):
class TestStepConfig
{
string Name;
// Parameters are tuple of parameter name to parameter value. If parameter is not truly a string, it will be converted to int, float, etc later.
IReadOnlyList<Tuple<string, string>> Parameters;
}
interface ITester
{
// Return value is any data coming back from the test. First tuple element is result name, second is result value (I.E. "Voltage","5.0")
List<Tuple<string, string>> RunTestStep(TestStepConfig config);
}
class NaiveSequencer
{
List<TestStepConfig> configs;
ITester tester;
void RunFullTest()
{
foreach (var config in configs)
tester.RunTestStep(config);
}
}
L'idea è che ogni tester abbia una serie di passi di prova atomici che può eseguire. Conosce questi passaggi per nome e i passaggi contengono una serie di parametri come indicato nel campo Parametri di TestStepConfig. Quindi, si passa in un TestStepConfig con il nome del passo desiderato e dei parametri desiderati, e il tester esegue quella fase di test.
Quindi, tutto ciò che qualsiasi schema di configurazione deve fare è determinare quale TestStepConfigs inserire nel tester e tutto ciò che il tester deve capire è come eseguire questi TestSteps atomici.
Quello che mi ha guardato con questa soluzione è che "TestStepConfig" sembra a disagio come re-implementare una chiamata al metodo ("Nome" del metodo, "Parametri" da passare). Non voglio implementare i tester come un insieme effettivo di metodi specifici "test this, test that" perché:
- Potrebbero esserci molte, molte di queste fasi di test disponibili (ovunque da 20 a oltre 100), che porta a oggetti estremamente grandi e rigidi.
- Molti di questi test possono o non possono essere disponibili a seconda del particolare configurazione della panca (quale attrezzatura è disponibile, eccetera).
- Come viene eseguito un TestStep di un nome particolare può cambiare
a seconda della configurazione (quale parte viene testata, ecc.) - Devo essere in grado di eseguire sequenze di test con molte differenze tester, e non riesco a riscrivere tutti gli algoritmi di sequenziamento tempo c'è un nuovo tester solo perché ha un'interfaccia diversa
Per questi e altri motivi, i TestSteps che ritengo sono molto meglio modellati come un gruppo di qualcosa di simile a un Pattern di Comando (ma con parametri di esecuzione) riuniti da una fabbrica e inseriti in un'implementazione generica di un oggetto ITester , piuttosto che modellato come metodi in fase di compilazione del Tester.
Qualcuno ha avuto a che fare con un caso come questo prima? C'è uno schema migliore di quello che ho proposto sopra?