windows - Konfiguration af en mock interface i C ++

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg forsøger nu at bruge en bestemt SDK, som har mig at indlæse funktioner fra en DLL, som en leverandør giver .. Jeg er nødt til at videregive argumenter til disse funktioner, og DLL'en gør alt arbejdet ..


Nu skal DLL'en kommunikere med en anden enhed, mens jeg bare venter på resultaterne. Men jeg har ikke denne enhed, så hvordan konfigurerer jeg en mock interface for at efterligne enheden?


For at være klar, her er et eksempel:


myfuncpointer.Open(someparam,anotherparam,...);


Nu, fordi jeg ikke har enheden, kan DLL'en ikke udføre ovenstående funktion; det mislykkes. Hvordan konfigurerer jeg test, så DLL'en snakker til en klasse, jeg har designet i stedet for enheden? Er der nogen måde at omdirigere DLL'ens opkald til?


Hvordan laver jeg en DummyDevice-klasse til at gøre dette?


Tak..


P. S. Hvis noget ikke er klart, skal du ikke være for hurtig til at downvote. Kommenter hvad jeg skal forklare, og jeg vil forsøge at rydde op .. Tak.





EDIT: Hvad jeg har, er dog en spec sheet med alle de anvendte datastrukturer og de forventede/lovlige værdier, den skal indeholde. Så for eksempel, hvis jeg kalder en funktion:


myfuncpointer.getinfo(param,otherparam);


hvor en af ​​parameterne er en datastruktur, at DLL'en fylder op med info (siger, hvis en mulighed er aktiveret) efter at have forespurgt enheden .. Jeg kan gøre dette


param.option = true;


efter at det er færdig med getinfo-opkaldet.


Er det en god måde at teste koden på? Det ser ud til at være meget meget farligt at narre denne DLL til at tænke på alle de forkerte ting og synes at være virkelig virkelig svært at skalere selv lidt.

Bedste reference


Er emuleret enhedsadgang en stopgap løsning, indtil du får hardware? Hvis det er tilfældet, anbefaler jeg, at du finder en anden måde at være produktiv: arbejde på noget andet, skriv enhedsforsøg mv.


Er emuleret enhedsadgang et permanent krav? Hvis ja, her er et par tilgange, du kan tage:



  1. Hvis den anden leverandørs SDK har en 'simulering' eller 'emulering' -modus, skal du bruge den. Du er muligvis overrasket. Du er sandsynligvis ikke den eneste klient, der skal kunne test/kør deres applikation uden den anden leverandørs hardware installeret.

  2. Tag den anden sælgers kode ud af billedet. Emuler kun den funktionalitet, som din ansøgning har brug for, og baser den på dine programs krav. Alt er under din kontrol.


    en. Tilføj et indirektionslag. Brug polymorfisme til at skifte mellem to implementeringer: en, der kalder ind i den anden leverandørs DLL, og en der emulerer dens adfærd. Har din kode kald til en abstrakt basisklasse i stedet for direkte ringer til den anden sælger s DLL vil også gøre det nemmere at skrive enhedstest for din kode.


    b. Skriv en mock DLL (som Adam Rosenfield foreslog). Du skal nøjagtigt matche funktionsnavne og kaldkonventioner. Når du opgraderer til nye versioner af den anden leverandørs DLL, skal du udvide Mock DLL til at understøtte nye indgangspunkter, som din applikation bruger.


    Hvis du skal vælge hvilken DLL, der skal bruges på runtime, kan det kræve, at du konverterer din kode til at indlæse DLL'en dynamisk (men det lyder som om du måske allerede gør dette, da du sagde noget om funktionspegerne). Du kan muligvis beslutte at installere den tid, hvorvidt du skal installere den anden leverandørs DLL eller Mock DLL. Og hvis dette kun er til test, kan du muligvis vælge hvilken DLL, der skal bruges på kompileringstid, og bygg kun to versioner af din ansøgning.

  3. Skriv en mock-enhedsdriver (som andre har foreslået).


    Hvis du har specifikationen for grænsefladen mellem den anden leverandørs brugermodul DLL og deres enhedsdriver, kan dette være muligt. Det vil nok tage længere tid end nogen af ​​de andre tilgange, selvom du er en erfaren enhedsdriverudvikler, og især hvis du ikke har kilden til den anden sælger s DLL. UMDF (User Mode Driver Framework) kan gøre dette lidt lettere eller mindre tidskrævende.


    Hvis den angivne specifikation ikke beskriver bruger/kernel-grænsefladen, skal du omdanne denne grænseflade. Dette vil sandsynligvis ikke være en effektiv brug af din tid sammenlignet med de andre muligheder, især hvis drivergrænsefladen er kompleks (fx passerer den mange komplekse datastrukturer til DeviceIoControl()).


    I begge tilfælde skal du revidere dette hver gang du opgraderer til en ny version af den anden leverandørs SDK. De samme eksporterede DLL-funktioner kan kræve brug af nye DeviceIoControl() koder og strukturer.


Andre referencer 1


Det afhænger af, hvordan DLL'en har adgang til enheden. Hvis det gør det ved at kalde funktioner i en anden DLL, kan du levere en mock DLL, hvor du har erstattet de relevante funktioner. Men hvis DLL'en gør noget lavt niveau, som f.eks. At kalde direkte ind i kernen, går du igen at have en meget hårdere tid. I så fald skal du nok skrive en ny enhedsdriver eller kerneforlængelse eller noget.

Andre referencer 2


Der er en række steder, hvor du kan indsætte en mock objekt:



  1. Mock opkald til DLL'en : Skriv en Facade/wrapper klasse, der indkapsler funktionspegeropkaldene til leverandørens DLL i din ansøgning. Dette er en god ide generelt, fordi du kan sætte en renere klasse API over DLL-funktionen opkald. [7]

  2. Mock DLL : Skriv din egen DLL, der emulerer

  3. Mock enheden : Skriv en enhedsdriver, der emulerer enheden. Jeg vil ikke anbefale dette, fordi det vil være en masse arbejde og efterligne enhedens adfærd (herunder fejl og quirks) vil være svært.



Jeg vil anbefale # 1 , fordi det er den mindste mængde arbejde, og det er ikke kaste væk kode.


Facade klassen interface du designer til at skjule opkaldet i leverandørens DLL vil forbedre designet af din anden kode. Det vil reducere din kodes kobling med de lavt implementerede detaljer om leverandørens DLL og API'er. sælger leverer nye DLL API'er, vil du være i stand til at integrere det med din kode lettere. Du kan endda være i stand til at erstatte denne leverandørs DLL med en anden leverandør eller enhed. :)

Andre referencer 3


Du skal sandsynligvis skrive en enhedsdriver til det. Afhængigt af din platform kan du være tilgængelige enheder, der kan fungere for dig (dvs. ting som 'lo' -grænsefladen i Linux).


Du er ikke den første person, der har dette problem, så sørg for og aftør internettet, før du ruller din egen :-)

Andre referencer 4


Hvis DLL'en kommunikerer med en ekstern hardwareenhed, skal du implementere en driver, der er kompatibel med den aktuelle driver, men med emulerede svar.


Sandsynligvis, hvis du ikke har enheden, vil SDK alligevel være ubrugelig. Hvis der er nogen funktionalitet, forudsat at den ikke vedrører denne eksterne enhed, vil det næsten helt sikkert være lettere at oprette et tilsvarende bibliotek uden hardwareafhængigheden.

Andre referencer 5


Jeg har brugt en relativt heldig, ikke-bærbar metode til mocking-funktioner, i WIN32-miljøet (jeg tror det er kun 32 bit, men ikke sikkert). her er det:


#define INJECTED\_BYTES  5

static void replace\_target(void *Target, void *Server)
{
    DWORD dwOld;

    VirtualProtect(Target, INJECTED\_BYTES, PAGE\_WRITECOPY, &dwOld);
    *((unsigned char *)Target)++ = 0xe9 ;   // jump relative
    *(unsigned int *)Target = (unsigned int)((unsigned char *)Server - (unsigned char *)Target)-4;
    VirtualProtect(((unsigned char *)Target)-1, INJECTED\_BYTES, PAGE\_EXECUTE, &dwOld);
    FlushInstructionCache(GetCurrentProcess(), 0, 0);
}


Hvad dette gør er det erstatter de første par bytes af målfunktionen med et spring til din mocked funktion. Så når du ringer målet, hopper det direkte til din stub. Husk bare at beholde en kopi af de erstattede bytes (INJECTED\_BYTES), så du kan senere fortryde din mock.


Kom til at tænke på det, hvad der stopper dig fra at skrive din egen DLL, der kun stubber ud, hvad den virkelige DLL gør?