Wyniki egzaminu

Informacje o egzaminie:
  • Zawód: Technik programista
  • Kwalifikacja: INF.04 - Projektowanie, programowanie i testowanie aplikacji
  • Data rozpoczęcia: 21 kwietnia 2026 10:07
  • Data zakończenia: 21 kwietnia 2026 10:26

Egzamin zdany!

Wynik: 30/40 punktów (75,0%)

Wymagane minimum: 20 punktów (50%)

Nowe
Analiza przebiegu egzaminu- sprawdź jak rozwiązywałeś pytania
Pochwal się swoim wynikiem!
Szczegółowe wyniki:
Pytanie 1

Jakiego typu testy są stosowane do sprawdzania funkcjonalności prototypu interfejsu?

A. Testy zgodności
B. Testy obciążeniowe
C. Testy interfejsu
D. Testy efektywnościowe
Testy interfejsu są kluczowe w procesie weryfikacji funkcji prototypu interfejsu użytkownika. Testy te koncentrują się na sprawdzeniu poprawności działania wszystkich elementów graficznych, takich jak przyciski, pola tekstowe, menu rozwijane oraz formularze. Testy interfejsu pozwalają upewnić się, że interakcje użytkownika z aplikacją przebiegają zgodnie z oczekiwaniami i nie powodują błędów w nawigacji. Dzięki nim można wykryć problemy związane z nieprawidłowym rozmieszczeniem elementów, brakiem reakcji na kliknięcia lub nieintuicyjnym działaniem, co pozwala na wczesne wdrożenie poprawek i zwiększenie użyteczności aplikacji.

Pytanie 2

Który z etapów umożliwia zwiększenie efektywności aplikacji przed jej wydaniem?

A. Testowanie jednostkowe
B. Optymalizacja kodu
C. Tworzenie interfejsu graficznego
D. Dodawanie komentarzy do kodu
Optymalizacja kodu to kluczowy etap poprawy wydajności aplikacji przed jej publikacją. Polega na eliminacji zbędnych operacji, poprawie algorytmów oraz minimalizacji użycia zasobów, co pozwala na szybsze działanie aplikacji i zmniejszenie jej zapotrzebowania na pamięć. Optymalizacja kodu obejmuje również refaktoryzację, czyli przekształcenie kodu w bardziej czytelną i efektywną formę bez zmiany jego funkcjonalności. Dzięki optymalizacji aplikacje działają płynniej, szybciej się ładują i oferują lepsze doświadczenie użytkownika, co ma kluczowe znaczenie dla SEO oraz pozycjonowania aplikacji w wyszukiwarkach. Dodatkowo, zoptymalizowany kod jest łatwiejszy w utrzymaniu i rozwijaniu, co przekłada się na długoterminowe korzyści dla zespołu deweloperskiego.

Pytanie 3

Co zostanie wyświetlone po wykonaniu poniższego kodu JavaScript?

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success');
  }, 1000);
});

promise
  .then(res => {
    console.log(res);
    return 'first then';
  })
  .then(res => {
    console.log(res);
  });
A. first then
B. first then, success
C. success
D. success, first then
Podany kod JavaScript korzysta z obietnic (Promises), co jest nowoczesnym podejściem do zarządzania asynchronicznością w JavaScript. W momencie, gdy tworzymy nową obietnicę, wykorzystujemy funkcję `setTimeout`, która po 1 sekundzie wywołuje metodę `resolve`, przekazując tekst 'success'. To jest pierwszy krok, w którym obietnica zostaje spełniona. Następnie, w łańcuchu `then`, pierwsza funkcja `then` przyjmuje wynik obietnicy, czyli 'success', loguje go na konsolę, a następnie zwraca nowy tekst 'first then'. Druga funkcja `then` odbiera ten wynik i również go loguje. W rezultacie na konsoli pojawią się kolejno: 'success' oraz 'first then'. Taki sposób tworzenia łańcuchów obietnic jest zgodny z najlepszymi praktykami programowania asynchronicznego w JavaScript, ponieważ pozwala na czytelniejsze i bardziej zrozumiałe zarządzanie kodem asynchronicznym, eliminując złożoność związaną z tzw. „callback hell”. Warto zaznaczyć, że obietnice mogą być stosowane do radzenia sobie z żądaniami sieciowymi, operacjami na plikach czy innymi długotrwałymi procesami, co czyni je niezbędnym narzędziem w nowoczesnym programowaniu webowym.

Pytanie 4

Jaki będzie wynik działania poniższego kodu JavaScript?

function foo() { console.log(a); var a = 1; console.log(a); } foo();
A. 1, 1
B. ReferenceError, 1
C. undefined, 1
D. undefined, undefined
Wynik działania podanego kodu to 'undefined, 1', co jest zgodne z zasadami hoisting w JavaScript. Kiedy funkcja 'foo' jest wywoływana, zmienna 'a' jest zadeklarowana przy użyciu 'var'. Zgodnie z zasadą hoisting, deklaracja zmiennej jest przenoszona na początek funkcji, ale przypisanie wartości następuje w miejscu, gdzie znajduje się kod. Dlatego, podczas pierwszego wywołania 'console.log(a)', 'a' nie ma jeszcze przypisanej wartości, co skutkuje wyświetleniem 'undefined'. Następnie, po przypisaniu '1' do 'a', w drugim 'console.log(a)' zmienna ta już ma wartość, więc wyświetlane jest '1'. Zrozumienie hoisting jest kluczowe dla programistów, ponieważ może wpływać na logikę działania kodu i prowadzić do błędów, jeśli nie jest odpowiednio uwzględnione. W praktyce powinno się unikać korzystania z hoisting, preferując inicjalizację zmiennych na początku funkcji, co zwiększa czytelność i utrzymanie kodu.

Pytanie 5

Wykorzystując jeden z dwóch zaprezentowanych sposobów inkrementacji w językach z rodziny C lub Java, można zauważyć, że
Zapis pierwszy:

b = a++;
Zapis drugi:
b = ++a;
A. Tylko przy użyciu pierwszego zapisu zmienna a zostanie zwiększona o 1.
B. Drugi zapis nie jest zgodny ze składnią, co doprowadzi do błędów kompilacji.
C. Wartość zmiennej b będzie wyższa po użyciu drugiego zapisu w porównaniu do pierwszego.
D. Bez względu na zastosowany sposób, w zmiennej b zawsze uzyskamy ten sam rezultat.
Drugi zapis nie jest niezgodny ze składnią – zarówno preinkrementacja, jak i postinkrementacja są w pełni zgodne z zasadami języka i nie powodują błędów kompilacji. Niezależnie od wybranego zapisu, zmienna zostanie zwiększona, lecz kluczowa różnica polega na tym, kiedy dokładnie to następuje. Twierdzenie, że w każdym przypadku wynik będzie taki sam, jest błędne – różnice pojawiają się podczas użycia tych operatorów w bardziej złożonych wyrażeniach. Zapis pierwszy (preinkrementacja) nie jest jedynym sposobem na zwiększenie wartości zmiennej, chociaż w wielu sytuacjach jest preferowany ze względu na efektywność.

Pytanie 6

Który z poniższych przypadków stanowi test niefunkcjonalny?

A. Sprawdzenie obsługi formularza rejestracji
B. Weryfikacja poprawności logowania użytkownika
C. Testowanie wydajności aplikacji pod dużym obciążeniem
D. Sprawdzenie działania przycisku
Testowanie wydajności aplikacji pod dużym obciążeniem to przykład testu niefunkcjonalnego. Jego celem jest ocena, jak aplikacja zachowuje się przy dużej liczbie użytkowników lub operacji jednocześnie. Testy te pozwalają na identyfikację wąskich gardeł i optymalizację kodu oraz infrastruktury serwerowej. W ramach testów obciążeniowych analizowane są parametry takie jak czas odpowiedzi, zużycie zasobów (CPU, RAM) oraz stabilność aplikacji w warunkach skrajnego obciążenia. Testowanie wydajności jest kluczowe w aplikacjach webowych, e-commerce oraz systemach o dużej liczbie transakcji, gdzie każdy przestój może generować straty finansowe i negatywnie wpływać na doświadczenia użytkownika.

Pytanie 7

Jakie znaczenie ma pojęcie "debugowanie" w kontekście programowania?

A. Wdrażanie aplikacji w środowisku produkcyjnym
B. Przygotowywanie dokumentacji kodu
C. Tworzenie nowych funkcjonalności aplikacji
D. Wyszukiwanie i usuwanie błędów w kodzie
Debugowanie to proces wyszukiwania i eliminowania błędów (bugów) w kodzie źródłowym programu. Polega na analizowaniu działania aplikacji linia po linii, śledzeniu wartości zmiennych, analizie stosu wywołań i wykrywaniu miejsc, w których program działa niezgodnie z oczekiwaniami. Debugowanie umożliwia programistom szybkie odnajdywanie błędów logicznych, składniowych oraz problemów z wydajnością aplikacji. Narzędzia takie jak Visual Studio, PyCharm, IntelliJ IDEA czy Chrome DevTools oferują zaawansowane funkcje debugowania, takie jak punkty przerwań (breakpoints), krokowe wykonywanie kodu i podgląd pamięci. Proces debugowania jest kluczowy w każdym etapie rozwoju oprogramowania, ponieważ znacząco wpływa na stabilność i jakość finalnego produktu.

Pytanie 8

Jakie jest główne zadanie debuggera w środowisku programowania?

A. Generowanie plików wykonywalnych
B. Analiza i usuwanie błędów w kodzie
C. Tworzenie kodu źródłowego
D. Kompilowanie kodu źródłowego
Debugger to narzędzie programistyczne służące do analizy i usuwania błędów w kodzie źródłowym. Pozwala na krokowe wykonywanie programu, śledzenie wartości zmiennych i identyfikowanie miejsc, w których występują błędy logiczne lub składniowe. Debugger umożliwia zatrzymanie wykonania programu w dowolnym miejscu, ustawienie tzw. breakpointów (punktów przerwania) i monitorowanie przepływu sterowania. Dzięki temu programista może dokładnie przeanalizować, dlaczego program nie działa zgodnie z oczekiwaniami i szybko znaleźć przyczynę problemu. Debuggery są dostępne w większości zintegrowanych środowisk programistycznych (IDE), takich jak Visual Studio, PyCharm czy IntelliJ IDEA.

Pytanie 9

Co to jest Cypress?

A. Framework do testowania end-to-end aplikacji webowych
B. Narzędzie do kompilacji kodu TypeScript
C. Biblioteka komponentów UI dla React
D. System zarządzania bazami danych dla aplikacji mobilnych
Cypress to popularny framework do testowania aplikacji webowych, skoncentrowany na testach end-to-end, co oznacza, że pozwala na symulowanie rzeczywistego użytkownika w interakcji z aplikacją. Jego architektura oparta na JavaScript i łatwość integracji z innymi narzędziami sprawiają, że jest chętnie wybierany przez zespoły developerskie. Cypress umożliwia szybkie pisanie testów, które mogą być uruchamiane bezpośrednio w przeglądarce, co ułatwia debugowanie. Przykładem zastosowania może być testowanie formularzy na stronie internetowej, gdzie można sprawdzić, czy wszystkie pola działają poprawnie, czy błędne dane są odpowiednio walidowane oraz czy interfejs użytkownika reaguje jak oczekiwano. Dobrą praktyką jest pisanie testów w sposób, który odzwierciedla rzeczywiste scenariusze użytkowników, co zwiększa jakość i niezawodność aplikacji. Cypress zyskał uznanie w branży dzięki swojej wydajności i możliwościom wizualizacji testów, co czyni go jednym z wiodących narzędzi w obszarze automatyzacji testów.

Pytanie 10

Jakie są cechy testów interfejsu?

A. Weryfikują zgodność aplikacji z przepisami prawnymi
B. Analizują wydajność aplikacji w czasie rzeczywistym
C. Sprawdzają prawidłowość pracy elementów graficznych oraz interakcji użytkownika z aplikacją
D. Ulepszają kod aplikacji
Testy interfejsu, znane też jako testy GUI (Graphical User Interface), są niesamowicie istotne w codziennej pracy programisty, zwłaszcza jeśli chodzi o aplikacje z graficznym interfejsem użytkownika. Ich głównym celem jest sprawdzanie, czy wszystkie elementy graficzne, takie jak przyciski, pola tekstowe czy menu działają zgodnie z założeniami oraz czy użytkownik może wchodzić z nimi w interakcję w przewidywany sposób. W praktyce zdarza się, że najwięcej błędów wychodzi właśnie na tym etapie – na przykład, kliknięcie w przycisk nie wywołuje żadnej akcji, albo okna dialogowe są nieczytelne. Moim zdaniem regularne wykonywanie takich testów (często automatycznych przy użyciu narzędzi typu Selenium, Cypress czy Playwright) pozwala wykrywać drobne usterki zanim trafią do rąk klienta, co jest zgodne z dobrymi praktykami Continuous Integration. Często też testy te są weryfikowane pod kątem responsywności, dostępności (WCAG) czy kompatybilności z różnymi przeglądarkami. Z mojego doświadczenia to właśnie testy interfejsu najbardziej pomagają w budowaniu pozytywnych doświadczeń użytkowników, bo pomagają wychwycić nieintuicyjne zachowania aplikacji, które ciężko zauważyć samym kodem. Warto więc o nich pamiętać, bo nawet najlepsza logika aplikacji nie obroni się, gdy UI nie działa poprawnie.

Pytanie 11

W standardzie dokumentacji testów oprogramowania IEEE 829-1998 opisany jest dokument, który zawiera dane o tym, jakie przypadki testowe były wykorzystane, przez kogo i czy zakończyły się sukcesem. Co to jest?

A. Plan Testów
B. Raport Podsumowujący Testy
C. Dziennik Testów
D. Specyfikacja Procedury Testowej
Pojęcie dokumentacji testowej według IEEE 829-1998 jest bardzo precyzyjne, ale często właśnie myli się niektóre pojęcia. Plan Testów to taki ogólny, strategiczny dokument – mówi, co, kiedy i jak będziemy testować, jakie są założenia, jakie środowisko i narzędzia, ale nie przechowuje szczegółowych informacji o tym, które przypadki były faktycznie realizowane danego dnia przez daną osobę. Trochę jak plan meczu przed rozgrywką, a nie jego protokół. Z kolei Specyfikacja Procedury Testowej to szczegółowy opis kroków, jakie należy wykonać, żeby przeprowadzić dany test – taki „przepis na testowanie”, który daje testerowi konkretną instrukcję działania. Ona nie zbiera jednak danych o tym, kto wykonał, kiedy i z jakim skutkiem – raczej mówi „jak” niż „kto/co/kiedy”. Raport Podsumowujący Testy natomiast to taki końcowy dokument na podsumowanie całego cyklu testowego – zestawia wyniki, ilość znalezionych defektów, procent pokrycia, rekomendacje dotyczące dalszych działań; nie zawiera jednak szczegółowych wpisów o przebiegu pojedynczych przypadków. Typowym nieporozumieniem jest myślenie, że to właśnie raport podsumowujący będzie zawierał „wszystko”, ale on służy bardziej do ogólnego przeglądu i prezentacji wyników, a nie do śledzenia przebiegu każdego testu z osobna. Często też błędnie utożsamia się Specyfikację Procedury z rzeczywistym wykonaniem – a przecież można mieć procedurę, której wcale nie wykonano lub wykonano ją tylko częściowo. To właśnie Dziennik Testów jest tym bieżącym zapisem z pola bitwy, gdzie widać realny przebieg procesu testowego, kto się czym zajmował, czy pojawiły się jakieś nieprzewidziane sytuacje. W praktyce brak tego dziennika często prowadzi do chaosu i problemów z rozliczalnością – a przecież to klucz do profesjonalnego testowania, zgodnie z branżowymi standardami.

Pytanie 12

Przedstawione w filmie działania wykorzystują narzędzie

A. generatora GUI przekształcającego kod do języka XAML
B. generatora kodu java
C. kompilatora dla interfejsu graficznego
D. debuggera analizującego wykonujący kod
Wybrana odpowiedź jest trafna, bo faktycznie narzędzie pokazane w filmie to generator GUI, który potrafi przekształcać kod do języka XAML. XAML (czyli Extensible Application Markup Language) jest powszechnie używany do deklaratywnego opisywania interfejsów użytkownika, na przykład w aplikacjach WPF czy UWP na platformie .NET. Jak dla mnie, korzystanie z takich generatorów to ogromna wygoda, bo pozwala błyskawicznie przenosić projekt graficzny do formatu czytelnego dla platformy Microsoftu. Z mojego doświadczenia, wiele zespołów programistycznych stosuje takie rozwiązania, żeby oszczędzić czas na ręcznym pisaniu XAML-a (co potrafi być naprawdę żmudne przy dużych projektach). Co ciekawe, takie narzędzia bardzo dobrze współpracują z designerskimi edytorami UI i potrafią zautomatyzować konwersję nawet z innych formatów graficznych, np. Sketch czy Adobe XD do XAML-a. Branżowe standardy zalecają, by wykorzystywać generatorów GUI właśnie do tego celu, bo minimalizuje to liczbę błędów, przyspiesza wdrożenie zmian i ułatwia współpracę między programistami a projektantami. Warto pamiętać, że XAML jest bardzo elastyczny i umożliwia potem ręczną edycję wygenerowanego kodu – czasem powstają drobne poprawki, ale ogólnie to naprawdę przydatne narzędzie. Ogólnie – jeśli tylko projektujesz UI pod .NET, to automatyczna konwersja do XAML-a to jest coś, co warto znać i wykorzystywać w praktyce.

Pytanie 13

Zaprezentowany diagram ilustruje wyniki przeprowadzonych testów:

Ilustracja do pytania
A. ochrony
B. funkcjonalności
C. użyteczności
D. wydajnościowych
To właśnie są testy wydajnościowe – dokładnie takie parametry jak czasy ładowania, liczba żądań HTTP, rozmiar przesyłanych danych czy ilość przekierowań analizuje się w praktyce podczas oceny wydajności stron internetowych. Moim zdaniem ten typ testów jest absolutnie kluczowy w projektowaniu nowoczesnych aplikacji webowych, bo użytkownicy szybko rezygnują, jeśli strona się długo ładuje albo jest zbyt zasobożerna. W branży zwraca się obecnie ogromną uwagę na to, by strony były 'lekkie', szybkie i zoptymalizowane pod kątem przesyłu danych. Nawet Google premiuje szybkie serwisy w wynikach wyszukiwania, co niejeden programista już odczuł na własnej skórze. Testy wydajnościowe sprawdzają, jak aplikacja zachowuje się pod dużym obciążeniem i ile danych realnie pobierają użytkownicy. W praktyce polecam korzystać z narzędzi takich jak Google Lighthouse, WebPageTest czy nawet prosty DevTools w przeglądarce – pozwalają szybko wyłapać największe problemy z czasem ładowania. Warto też pamiętać, że optymalizacja wydajności to nie tylko lepsze wrażenia użytkownika, ale bardzo wymierne oszczędności na transferze i infrastrukturze. Dobry zwyczaj to cyklicznie monitorować te wskaźniki, nawet gdy wydaje się, że wszystko działa OK – bo sytuacja może się szybko zmienić po wdrożeniu nowych funkcjonalności lub zmianach w kodzie.

Pytanie 14

W klasie pracownik zdefiniowano następujące metody:

pracownik()   { ... }
static void wypisz()   { ... }
int operator== (const pracownik &prac) { ... }
~pracownik()   { ... }
Która z nich jest odpowiednia do dodania elementu diagnostycznego o treści:
cout << "Obiekt został usunięty";
Ilustracja do pytania
A. wypisz
B. operator==
C. pracownik
D. ~pracownik
Destruktor to specjalna metoda w języku C++ oznaczona tyldą przed nazwą klasy która jest wywoływana automatycznie w momencie usuwania obiektu danego typu z pamięci. Dlatego dodanie elementu diagnostycznego cout<<Obiekt został usunięty; jest najbardziej sensowne w destruktorze ponieważ pozwala na śledzenie momentu w którym obiekt przestaje istnieć. Takie podejście jest zgodne z dobrymi praktykami programistycznymi ponieważ pomaga w debugowaniu i zarządzaniu zasobami w programie. Warto zauważyć że destruktory są kluczowe w kontekście zarządzania pamięcią szczególnie gdy klasa dynamicznie alokuje zasoby. Wówczas destruktor powinien zawierać kod zwalniający te zasoby aby uniknąć wycieków pamięci. Dodawanie diagnostycznych komunikatów może pomóc programistom w identyfikacji potencjalnych błędów związanych z zarządzaniem cyklem życia obiektów i poprawić ogólną stabilność i czytelność kodu. Praktyka ta jest szczególnie ważna w dużych projektach gdzie ręczne śledzenie wszystkich obiektów byłoby trudne i czasochłonne. Warto stosować taką diagnostykę w połączeniu z nowoczesnymi narzędziami do profilowania i analizy pamięci co zwiększa efektywność procesu programistycznego.

Pytanie 15

Które z wymienionych narzędzi nie znajduje zastosowania w tworzeniu aplikacji desktopowych?

A. Edytor graficzny
B. Przeglądarka internetowa
C. Debugger
D. Kompilator
Przeglądarka internetowa nie jest narzędziem wykorzystywanym bezpośrednio w procesie tworzenia aplikacji desktopowych. Chociaż może służyć do przeszukiwania dokumentacji lub testowania aplikacji webowych, jej funkcjonalność nie wspiera bezpośredniego tworzenia aplikacji desktopowych. W tworzeniu aplikacji desktopowych kluczowe są narzędzia takie jak kompilatory, debugery i edytory kodu. Kompilatory przekształcają kod źródłowy na kod wykonywalny, debugery pozwalają na śledzenie błędów, a edytory kodu umożliwiają pisanie i edytowanie aplikacji.

Pytanie 16

Dlaczego w wyniku działania tego kodu w języku C++ na ekranie pojawiła się wartość 0 zamiast 50?

int oblicz(int x)  {
    int i = 50;
    x = x + i;
    return i;
}

int main()  {
    int x = 0;
    int wynik = oblicz(x);
    std::cout << x;
}
A. Funkcja zwraca wartość, chociaż nie powinna jej zwracać.
B. Zmienna x powinna być inicjowana wartością równą 1, a nie 0.
C. Argument funkcji został przekazany przez wartość, a nie przez referencję.
D. Niepoprawnie zdefiniowano działanie wewnątrz funkcji.
W C++ funkcje standardowo dostają argumenty przez wartość, co znaczy, że dostają kopię tego, co do nich wysyłamy. W tym kodzie, jak widzisz, zmienna x idzie do funkcji oblicz jako kopia. To sprawia, że jakiekolwiek zmiany w x w tej funkcji nie mają wpływu na x w funkcji main. Dlatego po wywołaniu oblicz(x) wartość x w main zostaje taka sama. Jeśli chcesz, żeby zmiany wewnątrz funkcji były widoczne w funkcji, która ją wywołuje, to musisz użyć przekazywania przez referencję. Robisz to, dodając & w deklaracji parametru funkcji, czyli robisz to tak: void oblicz(int &x). Przekazywanie przez referencję to dobra praktyka, gdy chcesz, aby funkcja mogła zmieniać wartość argumentu. A dodatkowo jest to efektywniejsze, bo unikasz kopiowania danych, co bywa kosztowne, szczególnie przy dużych strukturach danych.

Pytanie 17

Jaki będzie wynik działania poniższego kodu w języku C#?

int x = 5;
int y = 10;
Console.WriteLine($"Suma {x} i {y} wynosi {x + y}");
A. Suma 5 i 10 wynosi 15
B. Suma 5 i 10 wynosi x + y
C. Error: niewłaściwa składnia
D. Suma x i y wynosi 15
Kod w języku C# wykonuje operację dodawania dwóch zmiennych, x i y, oraz wyświetla wynik w sformatowanym ciągu tekstowym. Poprawna odpowiedź to 'Suma 5 i 10 wynosi 15', ponieważ zmienna x ma wartość 5, a zmienna y ma wartość 10. Kiedy dodajemy te dwie liczby, otrzymujemy 15. Warto zwrócić uwagę na wykorzystanie interpolacji ciągów, co jest istotnym elementem w nowoczesnym C#. Umożliwia to w prosty sposób łączyć tekst z wartościami zmiennych, co zwiększa czytelność kodu. Interpolacja jest szczególnie przydatna w kontekście generowania komunikatów użytkownika i raportów. Przykład zastosowania może obejmować aplikacje, które prezentują wyniki obliczeń lub statystyki, gdzie ważne jest, aby w przyjazny sposób przedstawiać dane. Dobre praktyki programistyczne sugerują, aby unikać twardego kodowania wartości zamiast tego używać zmiennych, co ułatwia późniejsze modyfikacje i utrzymanie kodu.

Pytanie 18

Który z wymienionych procesów NIE jest częścią etapu kompilacji?

A. Optymalizacja kodu
B. Analiza działania programu w czasie rzeczywistym
C. Tłumaczenie kodu źródłowego na język maszynowy
D. Weryfikacja błędów składniowych
Analiza działania programu w czasie rzeczywistym nie należy do etapu kompilacji, lecz do etapu wykonywania programu. Kompilacja obejmuje tłumaczenie kodu źródłowego na język maszynowy, optymalizację kodu i weryfikację błędów składniowych. Analiza w czasie rzeczywistym to rola debuggera, który działa na uruchomionym programie i umożliwia śledzenie jego działania krok po kroku.

Pytanie 19

W przedstawionych funkcjonalnie równoważnych kodach źródłowych po przeprowadzeniu operacji w zmiennej b zostanie zapisany wynik:

Python:C++/C#/Java:
x = 5.96;
b = int(x);
double x = 5.96;
int b = (int)x;
A. 6
B. 5
C. 5.96
D. 596
Odpowiedź 5 jest prawidłowa, bo w większości popularnych języków programowania, takich jak Python, C++, C#, czy Java, rzutowanie liczby zmiennoprzecinkowej (czyli typu float lub double) na typ całkowity (int) powoduje odcięcie części ułamkowej, a nie zaokrąglenie. To jest bardzo ważne, bo wiele osób intuicyjnie spodziewa się zaokrąglenia, a tu po prostu wszystko po przecinku ląduje w koszu. W przypadku podanego przykładu zmienna x ma wartość 5.96, ale po rzutowaniu na int, zarówno w Pythonie poprzez funkcję int(), jak i w pozostałych językach przez klasyczne rzutowanie (int)x, zostaje tylko 5. Dokładnie tak działa konwersja: odcina się część po przecinku niezależnie od tego, jak blisko liczba jest kolejnej całości. To niesamowicie przydatne np. podczas pracy z indeksami tablic albo gdy chcemy szybko zamienić wynik dzielenia na liczbę całkowitą. W praktyce, warto pamiętać, że takie rzutowanie nie wykonuje żadnej walidacji ani sprawdzania – jeśli liczba jest ujemna, to po prostu też odcina część ułamkową w kierunku zera, więc int(-5.96) da -5. Z mojego doświadczenia bardzo często spotyka się błąd w kodzie, kiedy ktoś oczekuje zaokrąglenia i nie otrzymuje go, bo rzutowanie zawsze odcina, nie zaokrągla. Warto znać tę różnicę przy projektowaniu algorytmów i korzystać np. z funkcji round() jeśli potrzebujemy zaokrąglenia, a nie odcinania. To takie małe niuanse, ale potem wchodzą w nawyk i bardzo ułatwiają życie podczas kodowania.

Pytanie 20

Jakie narzędzie jest wykorzystywane do zgłaszania błędów w projektach IT?

A. Blender
B. JIRA
C. Git
D. Photoshop
JIRA to jedno z najczęściej wykorzystywanych narzędzi do zarządzania projektami i raportowania błędów w projektach informatycznych. JIRA umożliwia śledzenie błędów, zarządzanie zadaniami oraz efektywne monitorowanie postępów prac nad projektem. Dzięki integracji z innymi narzędziami, takimi jak Confluence czy Bitbucket, JIRA stanowi kompleksowe rozwiązanie wspierające zespoły deweloperskie. Raportowanie błędów w JIRA pozwala na łatwe przypisywanie ich do odpowiednich członków zespołu, dodawanie załączników i komentarzy oraz monitorowanie statusu danego problemu, co usprawnia proces zarządzania jakością oprogramowania.

Pytanie 21

Jakie elementy powinny być ujęte w dokumentacji programu?

A. Opis funkcji, klas i zmiennych w kodzie
B. Strategia marketingowa aplikacji
C. Zestawienie błędów zidentyfikowanych w trakcie testów
D. Szczegóły dotyczące konfiguracji serwera
Opis funkcji, klas i zmiennych w kodzie to kluczowy element dokumentacji programu. Tego rodzaju dokumentacja pozwala na lepsze zrozumienie struktury aplikacji, jej logiki biznesowej oraz wzajemnych zależności pomiędzy poszczególnymi komponentami. Dokumentacja techniczna obejmuje szczegółowe informacje na temat implementacji, interfejsów API, schematów baz danych oraz sposobów integracji z innymi systemami. Dzięki niej programiści mogą szybciej wdrażać się w projekt, a błędy i niejasności są minimalizowane. Kompleksowa dokumentacja zawiera także przykłady użycia poszczególnych funkcji, co dodatkowo ułatwia rozwój i rozbudowę aplikacji. W dobrze prowadzonym projekcie dokumentacja kodu jest na bieżąco aktualizowana, co zwiększa jego przejrzystość i wspiera proces refaktoryzacji.

Pytanie 22

Jakiego kodu dotyczy treść wygenerowana w trakcie działania programu Java?

Ilustracja do pytania
A. Kodu 4
B. Kodu 1
C. Kodu 3
D. Kodu 2
W przypadku kodu 4 mamy do czynienia z operatorem modulo zastosowanym na zmiennych x i y. Wiąże się to z próbą podziału przez zero co w języku Java skutkuje wygenerowaniem wyjątku java.lang.ArithmeticException. Przykładowo jeśli y wynosi zero to operacja x % y jest niedozwolona i spowoduje wyjątek. Rozumienie jak bezpiecznie wykonywać operacje arytmetyczne w Javie jest kluczowe dla unikania takich błędów. Zgodnie z dobrymi praktykami należy zawsze sprawdzać wartości zmiennych przed wykonaniem operacji matematycznych które mogą prowadzić do błędów wykonania programu. Ważne jest aby stosować techniki obsługi wyjątków try-catch które pozwalają na przechwycenie i odpowiednie zarządzanie błędami. Używanie odpowiednich testów jednostkowych może pomóc w wcześniejszym wykryciu takich problemów co jest standardem w branży programistycznej. Zrozumienie obsługi błędów w programowaniu pozwala na tworzenie bardziej niezawodnych i odpornych na błędy aplikacji co jest istotnym aspektem pracy profesjonalnego programisty.

Pytanie 23

Co oznacza pojęcie TDD w kontekście programowania?

A. Test-Driven Development - praktyka pisania testów przed implementacją kodu
B. Task Deployment Diagram - schemat wdrażania zadań w projekcie
C. Technical Design Document - dokumentacja techniczna projektu
D. Type Definition Document - dokumentacja typów danych w aplikacji
Test-Driven Development (TDD) to metodologia programowania, w której proces tworzenia kodu zaczyna się od pisania testów. TDD polega na cyklicznym podejściu do rozwoju oprogramowania, w którym najpierw definiujemy, jakie funkcjonalności będzie miał nasz kod, a następnie implementujemy tylko te elementy, które są niezbędne do przejścia wcześniej napisanych testów. Dzięki temu, deweloperzy mają możliwość natychmiastowego sprawdzenia poprawności swojego kodu, co sprzyja eliminacji błędów na wczesnym etapie. Przykład zastosowania TDD można zobaczyć w tworzeniu aplikacji webowych, gdzie programista pisze testy jednostkowe dla nowych funkcji, a następnie implementuje te funkcje, poprawiając kod tylko w przypadku, gdy testy nie przechodzą. Takie podejście pozwala na zwiększenie jakości oprogramowania oraz jego łatwiejszą refaktoryzację. Warto również zauważyć, że TDD jest zgodne z praktykami Agile i Continuous Integration, co pozwala na efektywniejsze zarządzanie projektem i dostosowywanie go do wymagań zmieniającego się rynku.

Pytanie 24

Które z poniższych jest podstawowym rodzajem testów używanych w testowaniu jednostkowym?

A. Testy jednostkowe
B. Testy integracyjne
C. Testy akceptacyjne
D. Testy systemowe
Testy jednostkowe są kluczowym elementem procesu testowania oprogramowania, szczególnie w kontekście metodologii programowania zwinnego. Polegają one na testowaniu pojedynczych najmniejszych części programu, takich jak funkcje czy metody, w izolacji od reszty systemu. Dzięki temu możemy szybko wykryć błędy i upewnić się, że dany fragment kodu działa zgodnie z oczekiwaniami. W praktyce, testy jednostkowe są często automatyzowane i stanowią podstawę dla procesu ciągłej integracji (CI). Przykładem zastosowania testów jednostkowych może być sprawdzenie, czy funkcja dodająca dwie liczby zwraca poprawny wynik dla różnych zestawów danych wejściowych. Dzięki testom jednostkowym programiści mogą z większą pewnością modyfikować i rozwijać kod, mając pewność, że nie wprowadzają nowych błędów. To właśnie testy jednostkowe pozwalają na szybkie wykrywanie regresji i są fundamentem dla bardziej zaawansowanych form testowania, takich jak testy integracyjne czy systemowe. Dbanie o dobrze zdefiniowany zestaw testów jednostkowych jest uznawane za dobrą praktykę w branży IT i podnosi jakość oprogramowania.

Pytanie 25

Co zostanie wyświetlone po wykonaniu poniższego kodu?

function Person(name) {
  this.name = name;
}

Person.prototype.sayHello = function() {
  return `Hello, ${this.name}!`;
};

const person = new Person('John');
console.log(person.sayHello());
A. Hello, [object Object]!
B. TypeError: person.sayHello is not a function
C. Hello, undefined!
D. Hello, John!
Pierwsza z niepoprawnych odpowiedzi sugeruje, że wynik to 'Hello, undefined!'. To wynika z błędnego założenia, że właściwość 'name' nie jest prawidłowo przypisana do obiektu. W kodzie właściwość 'name' jest poprawnie ustawiona przez konstruktor, więc nie ma podstaw do uznania, że zwróci 'undefined'. Warto zauważyć, że 'undefined' pojawia się, gdy zmienne nie zostały zainicjowane lub gdy nie odnajdujemy właściwości w obiekcie. Z kolei opcja, która wskazuje na 'TypeError: person.sayHello is not a function', jest oparta na błędnym założeniu, że metoda 'sayHello' nie istnieje w obiekcie 'person'. Metoda ta została zdefiniowana w prototypie, więc każda instancja obiektu 'Person' ma do niej dostęp i nie spowoduje to błędu typu. Ostatnia z odpowiedzi, sugerująca, że wynik to 'Hello, [object Object]!', jest efektem niepoprawnego użycia konwersji obiektu do stringa. Gdybyśmy próbowali zwrócić 'this' jako obiekt bez odpowiedniego przetworzenia, zwróciłoby to domyślną reprezentację obiektu. Kluczowym błędem w myśleniu jest nieuwzględnienie, że metody są częścią prototypów i obiekty dziedziczą je, co jest fundamentalnym założeniem obiektowego paradygmatu programowania w JavaScript. Warto zwrócić uwagę na te koncepcje, aby lepiej zrozumieć działanie prototypów w tym języku.

Pytanie 26

Co to jest event bubbling w JavaScript?

A. Proces, w którym zdarzenie zaczyna się od najbardziej szczegółowego elementu i propaguje w górę hierarchii DOM
B. Technika optymalizacji wydajności zdarzeń na stronie
C. System powiadomień o błędach w konsoli JavaScript
D. Metoda zarządzania kolejką zdarzeń w aplikacjach asynchronicznych
Zrozumienie koncepcji event bubbling jest kluczowe dla pracy z interaktywnymi aplikacjami webowymi, a nieprawidłowe interpretacje mechanizmu zdarzeń mogą prowadzić do wielu problemów w codziennej pracy programisty. Twierdzenie, że event bubbling jest techniką optymalizacji wydajności zdarzeń na stronie, jest mylące, ponieważ owszem, skuteczne wykorzystanie event bubbling może poprawić wydajność, ale sam mechanizm nie jest techniką optymalizacji. Zamiast tego, jest to naturalna cecha modelu zdarzeń w JavaScript, która umożliwia propagację zdarzeń w hierarchii DOM. Warto również zauważyć, że zarządzanie kolejką zdarzeń w aplikacjach asynchronicznych to zupełnie inny temat, który dotyczy asynchroniczności oraz mechanizmu event loop, a nie procesu przekazywania zdarzeń. Dodatkowo, twierdzenie, że event bubbling jest systemem powiadomień o błędach w konsoli JavaScript, wprowadza w błąd, gdyż event bubbling dotyczy jedynie propagacji zdarzeń interfejsu użytkownika, a nie obsługi błędów czy logowania. Często nieporozumienia te wynikają z braku znajomości podstawowych zasad dotyczących zdarzeń w JavaScript oraz z pomylenia różnych mechanizmów, które wspierają interaktywność aplikacji. Dobrze jest zapoznać się z dokumentacją i przykładami, aby lepiej zrozumieć te kluczowe koncepcje.

Pytanie 27

Testy mające na celu identyfikację błędów w interfejsach między modułami bądź systemami nazywane są testami

A. bezpieczeństwa
B. wydajnościowymi
C. jednostkowymi
D. integracyjnymi
Testy integracyjne mają na celu wykrycie błędów w interfejsach i połączeniach między modułami lub systemami. Głównym celem tych testów jest sprawdzenie, czy różne komponenty aplikacji współpracują ze sobą zgodnie z oczekiwaniami. Testy integracyjne są przeprowadzane po testach jednostkowych, ale przed testami systemowymi. W praktyce testy te obejmują scenariusze, w których kilka modułów wymienia dane lub współdziała w ramach wspólnego procesu. Integracja jest kluczowa dla zapewnienia, że cały system działa jako spójna całość, co minimalizuje ryzyko błędów na etapie produkcji i poprawia jakość końcowego produktu. Przykładem może być test komunikacji między modułem autoryzacji użytkowników a modułem płatności w aplikacji e-commerce.

Pytanie 28

Błędy w interpretacji kodu stworzonego za pomocą React.js lub Angular można wykryć dzięki

A. konsoli przeglądarki internetowej
B. wbudowanemu debuggerowi w danym środowisku
C. kompilatorowi języka JavaScript
D. narzędziom zainstalowanym po stronie serwera aplikacji
Konsola przeglądarki to naprawdę super narzędzie do śledzenia błędów w JavaScript, a szczególnie przydatna jest, gdy piszemy coś w React.js albo Angular. Dzięki niej możesz łatwo sprawdzać logi i błędy, a nawet na żywo testować różne fragmenty swojego kodu. To naprawdę szybki sposób, żeby znaleźć problemy, bez potrzeby grzebania w całym kodzie aplikacji.

Pytanie 29

Co będzie wynikiem wykonania poniższego kodu w języku C#?

string text = "hello world";
var result = string.Join("", text.Split(' ').Select(s => char.ToUpper(s[0]) + s.Substring(1)));
Console.WriteLine(result);
A. helloworld
B. HELLO WORLD
C. HelloWorld
D. Hello World
Wynikiem wykonania kodu nie jest 'HELLO WORLD', a przyczyna tego nieporozumienia tkwi w sposobie przetwarzania tekstu. Warto zauważyć, że kod nie wykonuje prostej konwersji wszystkich liter na wielkie, jak sugeruje ta odpowiedź. Zamiast tego, każda pierwsza litera każdego słowa jest zmieniana na wielką, a pozostałe litery pozostają w oryginalnym stanie, co w przypadku 'hello world' daje wyrażenie 'Hello World'. To zrozumienie jest kluczowe w programowaniu, ponieważ często błędnie zakładamy, że transformacje na tekstach działają w sposób jednorodny. Inną niepoprawną odpowiedzią jest 'helloworld', która również pomija konwersję pierwszych liter na wielkie, co jest kluczowym aspektem działania kodu. Warto rozważyć, że przy pracy z tekstami w C# istotne są szczegóły, takie jak wielkość liter, a dobre praktyki programistyczne wymagają zrozumienia, jak funkcje manipulujące tekstem działają. Niepoprawne odpowiedzi często wynikają z niezrozumienia schematu, jakim jest łączenie, a nie tylko konwersji liter. Użytkownicy powinni zawsze testować swoje założenia poprzez praktyczne próby w kodowaniu, aby unikać takich nieporozumień.

Pytanie 30

Jakie elementy powinny być uwzględnione w scenariuszu testów aplikacji?

A. Zestaw kroków do testowania, oczekiwanych rezultatów oraz warunków początkowych
B. Strategia wdrożenia aplikacji w środowisku produkcyjnym
C. Dokumentacja techniczna oprogramowania
D. Dokładne wytyczne dotyczące realizacji kodu
Scenariusz testowy aplikacji powinien zawierać szczegółowy opis kroków testowych, oczekiwane wyniki oraz warunki wstępne, które muszą być spełnione przed rozpoczęciem testu. Scenariusz testowy to kluczowy dokument w procesie testowania oprogramowania, który pozwala na systematyczne i dokładne sprawdzenie, czy aplikacja działa zgodnie z oczekiwaniami. Uwzględnienie kroków testowych pozwala na replikację testów, a opis warunków wstępnych zapewnia, że test jest przeprowadzany w odpowiednim środowisku.

Pytanie 31

Który z wymienionych poniżej przykładów ilustruje prawidłowy szkielet zarządzania wyjątkami w języku C++?

A. try { kod } catch { obsługa }
B. try { kod } handle { obsługa }
C. try { kod } except { obsługa }
D. try { kod } finally { obsługa }
Jak to wygląda w C++? Kluczowym elementem jest szkielet z blokami 'try' i 'catch'. W bloku 'try' piszesz kod, który może spowodować błąd, a 'catch' zajmuje się sytuacjami, kiedy coś pójdzie nie tak. Dzięki temu nie musisz się martwić, że program nagle przestanie działać, bo masz kontrolę nad tym, jak reagować w trudnych momentach. Obsługa wyjątków to naprawdę ważna sprawa w programowaniu, bo pomaga wyłapać różne problemy, czy to z danymi, z pamięcią, czy z plikami. Z mojego doświadczenia, to po prostu sprawia, że aplikacje są bardziej stabilne i działa to na korzyść zarówno programisty, jak i użytkownika.

Pytanie 32

Co zostanie wypisane w konsoli po wykonaniu poniższego kodu JavaScript?

let a = { value: 10 }; let b = a; b.value = 20; console.log(a.value);
A. ReferenceError
B. 10
C. undefined
D. 20
Analizując błędne odpowiedzi, warto zwrócić uwagę na podstawowe zasady działania JavaScript w kontekście obiektów. Jeśli odpowiedzią byłoby 10, to sugerowałoby, że obiekt `a` nie został zmodyfikowany przez przypisanie do `b`, co jest nieprawdziwe. Obiekty w JavaScript są przekazywane przez referencję, co oznacza, że zmiana dokonana na jednym obiekcie wpływa na wszystkie referencje do niego. Odpowiedź `undefined` wskazywałaby na to, że obiekt `a` nie ma właściwości `value`, co również jest błędne, ponieważ obiekt `a` został zdefiniowany z tą właściwością i początkowo ma wartość 10. Z kolei `ReferenceError` występuje, gdy odwołujemy się do zmiennej, która nie istnieje w danym kontekście, co nie ma miejsca w naszym kodzie, ponieważ zarówno `a`, jak i `b` są zdefiniowane poprawnie. Błędy te często wynikają z niepełnego zrozumienia, jak JavaScript zarządza pamięcią i referencjami. Zrozumienie tych zasad jest kluczowe, aby unikać pułapek związanych z mutowalnością obiektów i przekazywaniem referencji, co może prowadzić do trudnych do diagnozowania błędów w większych projektach.

Pytanie 33

Po uruchomieniu poniższego kodu w języku C++ w konsoli pojawi się ciąg liczb:

int a = 1;
while (a++ < 6) {
    cout << a << " ";
}
A. 1 2 3 4 5
B. 1 2 3 4 5 6
C. 2 3 4 5 6
D. 2 3 4 5 6 7
No i właśnie, to jest świetny przykład na to, dlaczego zrozumienie działania operatora postinkrementacji w C++ jest kluczowe. W tym kodzie pętla while wykorzystuje zapis a++ < 6, czyli najpierw sprawdza warunek (porównuje bieżącą wartość a z 6), a dopiero potem zwiększa a o 1. To sprawia, że pierwszy raz sprawdzane jest, czy 1 < 6 – warunek prawdziwy – a dopiero potem a staje się 2. W bloku pętli wypisywane jest już zaktualizowane a, czyli 2. I tak aż do momentu, gdy a osiągnie 6 i warunek będzie fałszywy. W praktykach branżowych bardzo często spotyka się takie niuanse, szczególnie gdy pracuje się z indeksami tablic czy implementuje różne algorytmy. Dobrze jest zawsze pamiętać, jak działają operatory ++ i --, bo ich nieuważne użycie może prowadzić do trudnych do wychwycenia błędów. Warto też zauważyć, że takie rozwiązanie pozwala w prosty sposób uzyskać liczby od 2 do 6 bez dodatkowego zwiększania wartości w środku pętli. Moim zdaniem, jeśli rozumiesz ten mechanizm, to już jesteś o krok dalej niż wielu początkujących programistów – w praktyce docenisz to przy debugowaniu bardziej złożonych fragmentów kodu. A co do dobrych praktyk: zawsze staraj się pisać czytelny kod i nie mieszaj zbyt wielu operacji w jednym wyrażeniu, żeby później nie zastanawiać się, dlaczego wynik jest inny niż oczekiwany.

Pytanie 34

W przypadku przedstawionego fragmentu kodu Java, wyjątek zostanie zgłoszony, gdy wartość zmiennej index wyniesie:

try {
    int[] liczby = {1, 2, 3, 4, 5, 6};
    System.out.println(liczby[index]);
}
catch (Exception e) {
    System.out.println("wystąpił błąd.");
}
A. 0
B. 5
C. 1
D. 7
W podanym kodzie Java mamy do czynienia z tablicą o nazwie liczby zawierającą sześć elementów: {1 2 3 4 5 6}. Indeksy tablicy w Javie zaczynają się od 0 a kończą na n-1 gdzie n to długość tablicy. W tym przypadku tablica ma długość 6 a więc jej indeksy to 0 1 2 3 4 i 5. Kiedy próbujemy uzyskać dostęp do elementu tablicy za pomocą indeksu równego długości tablicy lub większego np. 6 w tym przypadku otrzymujemy wyjątek ArrayIndexOutOfBoundsException. Jest to standardowe zachowanie w języku Java mające na celu ochronę przed błędami związanymi z nieprawidłowym dostępem do pamięci. Tego rodzaju błędy mogą prowadzić do nieprzewidywalnych zachowań programów dlatego obsługa takich wyjątków jest dobrą praktyką programistyczną. Kod zawiera blok try-catch który przechwytuje wszelkie wyjątki w tym przypadku i drukuje komunikat aby poinformować użytkownika o błędzie. Takie podejście jest zgodne z zasadami bezpiecznego programowania oraz ułatwia debugging i zarządzanie błędami w aplikacjach produkcyjnych.

Pytanie 35

Jaki będzie wynik działania poniższego kodu w języku Java?

String a = "hello";
String b = "hello";
String c = new String("hello");
System.out.println(a == b);
System.out.println(a == c);
System.out.println(a.equals(c));
A. false, false, true
B. true, false, true
C. true, true, true
D. true, false, false
Wyniki, które wskazują, że zarówno porównanie 'a == c', jak i 'a.equals(c)' powinny zwracać 'true', opierają się na błędnym zrozumieniu, jak działa porównywanie obiektów w Javie. Warto zrozumieć, że operator '==' sprawdza, czy dwie referencje wskazują na ten sam obiekt w pamięci. W przypadku zmiennych 'a' i 'b', ponieważ obie są literałami tego samego ciągu, JVM optymalizuje ich przechowywanie, co skutkuje, że obie referencje prowadzą do tego samego obiektu. Natomiast zmienna 'c', utworzona za pomocą 'new String()', to zupełnie inny obiekt, mimo że jego wartość jest taka sama jak w 'a'. W związku z tym porównanie 'a == c' zwraca false. Z kolei metoda 'equals()' jest zaprojektowana do porównania wartości, a nie referencji, co oznacza, że 'a.equals(c)' zwróci true, ponieważ obie zmienne mają tę samą zawartość. Zrozumienie tych zasad jest kluczowe, aby unikać typowych pułapek przy pracy z obiektami w Javie. Pamiętaj, aby zawsze preferować 'equals()' do porównywania stringów i innych obiektów, aby uzyskać prawidłowe wyniki.”

Pytanie 36

Wskaż rodzaj testów, które przeprowadza się podczas fazy tworzenia kodu źródłowego

A. testy kompatybilności
B. testy wydajnościowe
C. testy jednostkowe
D. testy wdrożeniowe
Testy jednostkowe to, moim zdaniem, absolutny fundament solidnego programowania. Są to niewielkie, automatyczne testy, które programista pisze zwykle równolegle z kodem albo nawet przed nim, jeśli stosuje się TDD (Test-Driven Development). Chodzi o to, żeby każda najmniejsza część programu – funkcja, metoda czy klasa – była dokładnie sprawdzona, czy zachowuje się zgodnie z założeniami już na etapie pisania kodu. W praktyce wygląda to tak: piszesz sobie funkcję, która np. liczy VAT, i od razu piszesz kilka testów, które sprawdzają, czy dla różnych wartości zwraca ona poprawne wyniki. Gdy coś się zmieni w kodzie, testy jednostkowe pozwalają od razu wychwycić, że coś zepsułeś (albo, oby nie, ktoś inny). Standardy branżowe, jak np. ISTQB czy wytyczne IEEE 829, bardzo mocno podkreślają wagę testów jednostkowych – bez nich zarządzanie jakością oprogramowania jest po prostu niemożliwe na dłuższą metę. W praktyce nawet proste projekty szybko bez nich zamieniają się w chaos. Co ciekawe, dobrze napisane testy jednostkowe ułatwiają refaktoryzację, bo masz pewność, że po zmianach wszystko działa jak należy. W mojej opinii, jeśli ktoś naprawdę poważnie myśli o pracy w branży IT, powinien umieć pisać testy jednostkowe z marszu.

Pytanie 37

Wynikiem wykonania poniższego fragmentu kodu jest wyświetlenie liczb z zakresu od 2 do 20, które są

for (let number = 2; number <= 20; number++) {
    let check = true;
    for (let test = 2; test < number; test++) {
        if (number % test === 0) {
            check = false;
            break;
        }
    }
    if (check) console.log(number);
}
A. parzyste.
B. podzielne przez wartość zmiennej test.
C. podzielne przez wartość zmiennej check.
D. pierwsze.
Kod wypisuje liczby pierwsze, czyli takie, które mają dokładnie dwa dzielniki: 1 i samą siebie. Liczby pierwsze są podstawą w wielu dziedzinach matematyki i informatyki, szczególnie w kryptografii i algorytmach. Wyszukiwanie liczb pierwszych w danym przedziale to popularne zadanie, które pozwala na lepsze zrozumienie iteracji, pętli i warunków logicznych w programowaniu. Algorytm ten jest również wykorzystywany w optymalizacji algorytmów szyfrowania i generowania kluczy.

Pytanie 38

W języku C++, zakładając, że przedstawiony fragment kodu poprawnie się skompiluje i zostanie wykonany, to zmiennej liczba przypisana zostanie wartość:

int liczba = rand() % 1000;
A. dowolna pseudolosowa z przedziału typu int
B. rzeczywista podzielna przez 1000
C. równa 1000
D. pseudolosowa nie większa niż 999
Błędne odpowiedzi wynikają z niezrozumienia mechaniki działania funkcji rand() i operatora modulo w języku C++. Pierwsza koncepcja, że liczba mogłaby być równa 1000, jest błędna, ponieważ operator modulo ogranicza wynik do wartości mniejszych niż dzielnik, w tym przypadku 1000. Dlatego wynik nigdy nie osiągnie wartości 1000. Drugą błędną koncepcją jest przypisanie dowolnej liczby pseudolosowej w zakresie typu int. Funkcja rand() bez operacji modulo generuje liczby w zakresie od 0 do RAND_MAX, ale zastosowanie modulo 1000 zawęża ten zakres do wartości od 0 do 999. Trzecia koncepcja, że wynik musi być liczbą rzeczywistą podzielną przez 1000, wynika z błędnego założenia o typie danych i działaniach matematycznych. W kontekście języka C++ kod operuje na liczbach całkowitych, a nie rzeczywistych, i wynik modulo nie może być podzielny przez 1000, gdyż wartości te nigdy nie osiągną 1000. Kluczowe jest zrozumienie, że operacja modulo ogranicza zakres wyników i zapobiega wyjściu poza określoną wartość maksymalną, co jest fundamentalnym aspektem generowania liczb pseudolosowych w kontrolowanych zakresach. Dzięki temu podejściu można bezpiecznie i efektywnie wykorzystywać generowane wyniki w wielu zastosowaniach informatycznych, unikając typowych błędów logicznych i zakresowych w programowaniu.

Pytanie 39

Kompilator może wygenerować błąd "incompatible types", gdy

A. funkcja zwraca typ void, a w momencie wywołania nie jest przypisana do żadnej zmiennej
B. w trakcie deklaracji zmiennej wystąpił błąd, zastosowano nieistniejący typ
C. do zmiennej typu int przypisano wartość 243
D. funkcja oczekuje całkowitej jako argumentu, a została wywołana z napisem jako parametrem
Zła deklaracja zmiennej raczej spowoduje inne komunikaty o błędach, jak 'cannot find symbol', a nie 'incompatible types'. Jak przypisujesz liczbę do zmiennej typu int, to jest wszystko w porządku, więc błędu nie będzie. Pamiętaj, że funkcje typu void nie zwracają wartości, ale jeśli próbujesz coś przypisać, to dostaniesz raczej komunikat 'void type not allowed here'. To różne sprawy.

Pytanie 40

Co zostanie wyświetlone w konsoli po wykonaniu poniższego kodu?

console.log(typeof null);
console.log(typeof undefined);
console.log(typeof []);
console.log(typeof NaN);
A. null, undefined, array, number
B. object, undefined, array, number
C. null, undefined, object, NaN
D. object, undefined, object, number
Typowe błędy związane z błędnymi odpowiedziami wynikają często z mylnych koncepcji dotyczących typów danych w JavaScript. Warto zauważyć, że odpowiedź sugerująca, że null jest typem 'null' nie jest zgodna z rzeczywistością. Null nie jest odrębnym typem, lecz jest klasyfikowany jako obiekt, co jest wynikają z tego, że w JavaScript wszystko jest obiektowe z wyjątkiem prostych typów. Również opinia, że NaN powinien być uznawany za typ 'NaN' jest myląca. NaN jest specjalnym przypadkiem liczby, co można zobaczyć przy użyciu typeof. Tablica z kolei nie ma własnego typu w JavaScript, jest traktowana jako obiekt. To jest powód, dla którego typeof zwraca 'object' dla tablic. Niezrozumienie tych zasad prowadzi do błędnych konkluzji i może wpływać na jakość kodu. W praktyce powinno się zawsze stosować typeof do sprawdzania typów zmiennych, co zapewnia lepszą kontrolę nad danymi i eliminuje potencjalne błędy podczas wykonywania operacji na różnych typach. Warto zwracać uwagę na te aspekty, ponieważ wpływają one na wydajność i stabilność aplikacji.