Tillbaka till SDET

Testkoncept & Övningar

Looking for JavaScript fundamentals (variables, promises, classes…)? They live in the JavaScript path.Go to JavaScript →
Vilka typer av test doubles finns det?
En test double är vilken ersättare som helst för en riktig komponent. Dummy: skickas men används aldrig. Stub: returnerar fasta fördefinierade värden. Fake: en fungerande men förenklad implementation (t.ex. en databas i minnet). Spy: registrerar hur den anropades utan att ändra beteendet. Mock: en stub plus assertions om hur den anropades (t.ex. att sendEmail anropades en gång).
Varför och när mockar man — och när bör man inte?
Mocka för att isolera enheten som testas från långsamma eller instabila externa beroenden (databas, tredjeparts-API:er, e-post), för att simulera svåråterskapade fel som en 500, och för att hålla tester snabba och deterministiska. Mocka inte när du specifikt vill verifiera verklig integration, när en mock skulle avvika så mycket från verkligheten att den tappar värde, eller när det verkliga beroendet redan är lokalt och snabbt.
Hur mockar man nätverksanrop i Playwright?
Använd page.route för att fånga ett URL-mönster och uppfylla det med ett fördefinierat svar: page.route('**/api/products', r => r.fulfill({ status: 200, body: JSON.stringify(data) })). Du kan returnera en 500 för att testa fel-UI, eller lägga till en fördröjning före route.continue() för att testa laddningstillstånd — allt utan att röra den riktiga backenden.
Hur strukturerar man ett CRUD-integrationstest för ett REST-API?
Täck hela livscykeln och auth-/valideringsgränserna: skapa (POST -> 201), läs tillbaka (GET -> 200), uppdatera delvis (PATCH -> 200, oförändrade fält består), radera (DELETE -> 204) och bekräfta att den är borta (GET -> 404). Lägg till negativa fall: ingen token -> 401, fel roll -> 403, saknat obligatoriskt fält -> 422, dubblett -> 409. Varje test bör sätta upp sin egen data för att förbli oberoende.
Vad är TTL och var spelar det roll i testning?
TTL (time to live) är hur länge något förblir giltigt: auth-tokens/sessioner (JWT-utgång), cacheposter (Redis, CDN, HTTP Cache-Control) och rate-limit-fönster (X-RateLimit-Reset). Som SDET testar du att en utgången token avvisas, att en cachepost blir en miss efter sin TTL, och att begäranden över gränsen stryps och återställs korrekt.
Varför undvika fasta sleeps, och vad använder man i stället?
En fast sleep (waitForTimeout(3000)) är antingen för kort (flaky) eller för lång (långsam), eftersom verklig timing varierar. Använd villkorsbaserade väntningar i stället: waitForSelector för ett element, expect(...).toBeVisible(), waitForResponse för ett API-anrop, eller en generisk polling-hjälpare som kontrollerar ett villkor på nytt fram till en timeout. Detta gör testerna både snabbare och mer pålitliga.
Hur fungerar omförsök med exponentiell backoff, och när bör man inte göra omförsök?
Omförsök kör om en misslyckad operation upp till N försök och väntar längre mellan varje försök (delay * 2^försök) så att en kämpande tjänst kan återhämta sig utan att överbelastas. Gör endast omförsök vid övergående fel (nätverksglapp, 5xx, timeouts). Gör inte omförsök vid deterministiska klientfel som 404 eller 422 — ett shouldRetry-predikat låter dig hoppa över dem, eftersom omförsök aldrig kommer att lyckas.
Frågar intervjuare om användning av AI-verktyg, och hur bör en kandidat svara?
Ja, i nyliga tekniska intervjuer — särskilt för bättre betalda roller — är det vanligt att kandidater tillfrågas om de använder AI-verktyg, vilka verktyg de använder och hur de använder dem. Intervjuare bedömer inte bara om AI används, utan om det används medvetet och med genuin förståelse för resultatet. Ett starkt svar är att förklara att man använder AI för att accelerera uppgifter man redan behärskar, och att man alltid granskar och förstår den genererade koden eller förslagen. Vissa take-home-uppgifter kräver nu till och med en dedikerad fil (t.ex. AI_PROCESS.md) som dokumenterar hur AI användes under projektets gång.
Du har ett intermittent backend-problem — det inträffar ibland men inte alltid. Hur skulle du gå tillväga för att diagnostisera och lösa det?
Börja med att granska befintliga loggar för att identifiera mönster kring när problemet uppstår. Om loggning inte redan är implementerad, lägg till det på relevanta API:er och tjänster för att fånga HTTP-förfrågnings- och svarsdata inklusive statuskoder (t.ex. 200 OK, 500 Server Error, 400 Bad Request). Använd molnövervakningsverktyg som AWS CloudWatch om din infrastruktur stödjer det. Lägg till try/catch-block för att fånga och logga undantag vid felpunkten. Avgränsa sedan problemets omfattning: identifiera var i systemet det uppstår och under vilka förhållanden det visar sig — exempelvis tid på dagen, trafikbelastning eller specifika indatavärden. Överväg slutligen att implementera retry-logik för att hantera tillfälliga fel på ett robust sätt, eftersom intermittenta problem ofta orsakas av temporär otillgänglighet i nätverk eller resurser.
Under ett tekniskt urvalsprov visas du en pseudokod för en funktion som itererar över en array, ackumulerar summan av alla element och sedan delar med det totala antalet. Vad beräknar funktionen och vad är dess tidskomplexitet?
Funktionen beräknar det aritmetiska medelvärdet av elementen i arrayen. Tidskomplexiteten är O(n), eftersom algoritmen gör exakt ett genomlopp av alla n element för att ackumulera summan, följt av en konstant-tids division. Antalet operationer växer linjärt med storleken på indata.
Vad är skillnaden mellan att kontrollera Set-likhet och att beräkna Set-snitt när man jämför två arrayer?
Set-likhet (t.ex. set1.equals(set2) i Java) returnerar true bara om båda mängderna innehåller exakt samma element — det är en allt-eller-inget-kontroll. Set-snitt (t.ex. set1.retainAll(set2) i Java eller set(a) & set(b) i Python) returnerar delmängden av element som förekommer i båda samlingarna. När målet är att hitta vilka specifika element från en array som finns i en annan är snitt den korrekta operationen. Likhet är bara lämplig när du behöver verifiera att de två arrayerna innehåller exakt samma unika värden.
Vad är Test-Driven Development (TDD) och kan det tillämpas på en befintlig legacy-applikation?
TDD är en metodik där du skriver ett misslyckat test först, sedan skriver minimikoden för att det ska passera och slutligen refaktorerar. Man kan inte retroaktivt tillämpa TDD på kod som redan är skriven, men man kan anta TDD-disciplin för allt nytt arbete. För legacy-kod tillämpar man TDD-principer genom att lägga till karakteriseringstester innan befintlig logik refaktoreras, vilket skapar ett säkerhetsnät utan att behöva skriva om allt på en gång.
Skriv en rekursiv funktion för att beräkna fakulteten av ett tal. Vad är basfallet och hur hanteras kantfall?
En rekursiv fakultetsfunktion behöver två delar: 1. **Basfall** (stoppar rekursionen): när n är lika med 0 eller 1, returnera 1, eftersom 0! = 1! = 1. 2. **Rekursivt fall**: returnera n multiplicerat med factorial(n - 1). Pseudokod / generell form: funktion factorial(n): om (n == 0 || n == 1): returnera 1 annars: returnera n * factorial(n - 1) Viktiga punkter: - Definiera alltid basfallet först för att förhindra oändlig rekursion (stack overflow). - Lägg till en förhandsvillkor för negativa indata (t.ex. kasta ett fel), eftersom fakulteten inte är definierad för negativa tal. - Tidskomplexitet: O(n) — ett rekursivt anrop per dekrement. - Varje anrop placeras på call stack enligt LIFO-ordning; resultaten multipliceras när stacken rullas tillbaka.
Givet två heltalsarrayer, hur skulle du hitta de element som finns i båda (dvs. vilka element från den första arrayen förekommer också i den andra)?
Det finns flera tillvägagångssätt beroende på språk: **Java** – Konvertera båda arrayerna till List-objekt och använd retainAll(), som modifierar den första listan på plats så att den endast behåller element som också finns i den andra: java import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> list1 = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5)); List<Integer> list2 = new ArrayList<>(Arrays.asList(3, 4, 5, 6, 7)); list1.retainAll(list2); System.out.println("Gemensamma element: " + list1); // [3, 4, 5] } } **JavaScript** – Använd filter() kombinerat med includes(): javascript const array1 = [1, 2, 3, 4, 5]; const array2 = [3, 4, 5, 6, 7]; const gemensamma = array1.filter(element => array2.includes(element)); console.log(gemensamma); // [3, 4, 5] **Python** – Använd snittoperationen på mängder: python def gemensamma_element(a, b): return set(a) & set(b) Obs: Konvertering till mängder tar bort dubbletter. Om det är ett krav att bevara dubbletter från de ursprungliga arrayerna bör filterbaserat tillvägagångssätt användas istället.