{"id":33710,"date":"2026-05-04T05:00:00","date_gmt":"2026-05-04T03:00:00","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=33710"},"modified":"2026-04-30T14:43:05","modified_gmt":"2026-04-30T12:43:05","slug":"jak-naprawde-wyglada-kod-z-sii-testing-lab-otwieramy-repozytoria","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/jak-naprawde-wyglada-kod-z-sii-testing-lab-otwieramy-repozytoria\/","title":{"rendered":"Jak naprawd\u0119 wygl\u0105da kod z Sii Testing Lab? Otwieramy repozytoria"},"content":{"rendered":"\n<p>W badaniu <a href=\"https:\/\/sii.pl\/wp-content\/uploads\/2026\/04\/PL_SWM-30407-CC-Testing-Hackaton-testingowy-Testing-Lab-AI-Edition-1.pdf\" target=\"_blank\" rel=\"noopener\" title=\"\">Sii Testing Lab<\/a> opisali\u015bmy siedem kluczowych wniosk\u00f3w z naszego Hackathonu po\u015bwi\u0119conego roli AI w automatyzacji test\u00f3w. Publikacja spotka\u0142a si\u0119 z ogromnym zainteresowaniem, a liczba pyta\u0144 o techniczne szczeg\u00f3\u0142y, kt\u00f3re od Was otrzymali\u015bmy, przeros\u0142a nasze oczekiwania. W\u0142a\u015bnie dlatego zdecydowali\u015bmy si\u0119 przygotowa\u0107 ten komentarz.<\/p>\n\n\n\n<p>Cho\u0107 w raporcie potwierdzili\u015bmy, \u017ce AI podnosi efektywno\u015b\u0107, do\u015bwiadczenie testera ma istotne znaczenie, a modele maj\u0105 swoje ograniczenia, to tamte analizy (z natury rzeczy) pozosta\u0142y na poziomie uog\u00f3lnionych wniosk\u00f3w.<\/p>\n\n\n\n<p><strong>Ten artyku\u0142 to krok dalej.<\/strong> <strong>Schodzimy poziom ni\u017cej: do kodu, konkretnych decyzji implementacyjnych i moment\u00f3w, w kt\u00f3rych wyra\u017anie wida\u0107 granic\u0119 mi\u0119dzy mo\u017cliwo\u015bciami narz\u0119dzia a krytycznym my\u015bleniem in\u017cyniera.<\/strong><\/p>\n\n\n\n<p>Aby skupi\u0107 si\u0119 na tym, co wa\u017cne \u2013 na wzorcach i jako\u015bci kodu, a nie na rankingach \u2013 omawiam repozytoria anonimowo. Zale\u017cy mi na wyci\u0105gni\u0119ciu uniwersalnych lekcji, a nie na ocenie pracy poszczeg\u00f3lnych zespo\u0142\u00f3w.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Najpierw przypomnijmy, co oceniali\u015bmy<\/strong><\/h2>\n\n\n\n<p>Ka\u017cde repozytorium by\u0142o oceniane wed\u0142ug o\u015bmiu kryteri\u00f3w jako\u015bci:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>K1<\/strong> \u2013 Zgodno\u015b\u0107 testu z celem biznesowym i pokrycie wymaga\u0144.<\/li>\n\n\n\n<li><strong>K2<\/strong> \u2013 Dane testowe i przygotowanie stanu.<\/li>\n\n\n\n<li><strong>K3<\/strong> \u2013 Stabilno\u015b\u0107 rozwi\u0105zania.<\/li>\n\n\n\n<li><strong>K4<\/strong> \u2013 Jako\u015b\u0107 selektor\u00f3w i lokalizator\u00f3w.<\/li>\n\n\n\n<li><strong>K5<\/strong> \u2013 Architektura testu i wzorce.<\/li>\n\n\n\n<li><strong>K6<\/strong> \u2013 Jako\u015b\u0107 asercji.<\/li>\n\n\n\n<li><strong>K7<\/strong> \u2013 Diagnostyka i obs\u0142uga b\u0142\u0119d\u00f3w.<\/li>\n\n\n\n<li><strong>K8<\/strong> \u2013 Engineering.<\/li>\n<\/ul>\n\n\n\n<p>Ka\u017cde repozytorium zosta\u0142o oceniane w skali pi\u0119ciostopniowej, jednak oceny te nale\u017cy interpretowa\u0107 przez pryzmat specyfiki badania.<\/p>\n\n\n\n<p>Por\u00f3wnywali\u015bmy dwa podej\u015bcia:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>zespo\u0142y automatyzuj\u0105ce bez u\u017cycia AI (Oldschool),<\/li>\n\n\n\n<li>zespo\u0142y automatyzuj\u0105ce z u\u017cyciem AI (AI).<\/li>\n<\/ul>\n\n\n\n<p>Obie grupy mia\u0142y na prac\u0119 zaledwie 6 godzin, co determinowa\u0142o spos\u00f3b punktowania. Jury celowo przymyka\u0142o oko na nieuko\u0144czone modu\u0142y, priorytetyzuj\u0105c dojrza\u0142o\u015b\u0107 in\u017cyniersk\u0105 oraz jako\u015b\u0107 tego, co zosta\u0142o zrealizowane. Warto jednak zaznaczy\u0107, \u017ce dla grupy AI, kt\u00f3ra dzi\u0119ki technologii narzuci\u0142a znacznie szybsze tempo, poprzeczka by\u0142a postawiona odpowiednio wy\u017cej.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Grupa Oldschool: Dobra robota w trudnych warunkach<\/strong><\/h2>\n\n\n\n<p>Zanim wejdziemy w szczeg\u00f3\u0142y kodu, wa\u017cna uwaga kontekstowa: <strong>sze\u015b\u0107 godzin to naprawd\u0119 kr\u00f3tki czas na zbudowanie czegokolwiek od zera<\/strong>. Decyzje, kt\u00f3re wygl\u0105daj\u0105 jak uproszczenia, cz\u0119sto by\u0142y \u015bwiadomymi kompromisami wynikaj\u0105cymi z presji czasowej, a nie z braku wiedzy czy kompetencji.<\/p>\n\n\n\n<p>Maj\u0105c to w pami\u0119ci, przyjrzyjmy si\u0119 temu, co zespo\u0142y Oldschool faktycznie dostarczy\u0142y.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Testy przechodz\u0105, ale co weryfikuj\u0105?<\/strong><\/h3>\n\n\n\n<p>W repozytoriach Oldschool dominuje jeden powtarzaj\u0105cy si\u0119 wzorzec: <strong>sekwencja krok\u00f3w UI zako\u0144czona asercj\u0105 widoczno\u015bci elementu<\/strong>. Testy dzia\u0142aj\u0105, obejmuj\u0105 g\u0142\u00f3wne \u015bcie\u017cki u\u017cytkownika: logowanie, koszyk, <em>checkout<\/em>. Na pierwszy rzut oka wszystko wygl\u0105da poprawnie.<\/p>\n\n\n\n<p>Problem ujawnia si\u0119, gdy zadamy pytanie: Co tak naprawd\u0119 jest tutaj weryfikowane?<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ Typowy test z grupy Oldschool*\npublic void OrderPlacement() {\n    UserIsLoggedIn();\n    UserHasProductsAddedToCart();\n    _productPage.OpenBasket();\n    _productPage.ProceedWithOrder();\n    _addressFormPage.ClickContinue();\n    \/\/ ...\n    Assert.That(_orderConfirmationPage.ConfirmationMessage);\n}\n<\/pre><\/div>\n\n\n<p><em>* Przyk\u0142ad 1:1<\/em><\/p>\n\n\n\n<p>Test potwierdza, \u017ce <strong>proces si\u0119 zako\u0144czy\u0142, ale nie potwierdza, czy zako\u0144czy\u0142 si\u0119 poprawnie<\/strong>. Brakuje weryfikacji ceny, sprawdzenia zastosowanych rabat\u00f3w, poprawnego naliczenia podatk\u00f3w. Testy sprawdzaj\u0105 przep\u0142yw, nie logik\u0119 biznesow\u0105.<\/p>\n\n\n\n<p>Jak m\u00f3g\u0142by wygl\u0105da\u0107 ten sam test napisany z my\u015bl\u0105 o warto\u015bci biznesowej?<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ Test weryfikuj\u0105cy logik\u0119 biznesow\u0105*\n&#x5B;Test]\npublic void Should_Add_One_Product_To_Basket() {\n    CreatedProduct product = PrestashopTestDataService.CreateProductWithQuantity();\n    Driver.GoToUrl(Urls.Product(product.Url));\n    At&lt;ProductDetailsPage&gt;(x =&gt; x.AddToCart());\n    At&lt;CartPopupPage&gt;(x =&gt; {\n        x.ProductName.Should().Be(product.Name);\n        x.ProductQuantity.Should().Be(&quot;1&quot;);\n    });\n}\n<\/pre><\/div>\n\n\n<p><em>* .Be(&#8222;1&#8221;) zastosowane jako uproszczenie do zaprezentowania koncepcji<\/em><\/p>\n\n\n\n<p>R\u00f3\u017cnica jest zasadnicza: zamiast sprawdza\u0107, czy pojawi\u0142 si\u0119 komunikat o sukcesie, weryfikujemy konkretne warto\u015bci domenowe \u2013 nazw\u0119 produktu i ilo\u015b\u0107.<\/p>\n\n\n\n<p><strong>Warto odnotowa\u0107 pozytywny wyj\u0105tek w drug\u0105 stron\u0119:<\/strong> jeden z zespo\u0142\u00f3w Oldschool napisa\u0142 testy parametryzowane z negatywnymi przypadkami, czego nie zrobi\u0142 \u017caden zesp\u00f3\u0142 AI. Przyk\u0142ad pokazuje \u015bwiadomo\u015b\u0107, \u017ce warto testowa\u0107 nie tylko <em>happy path<\/em>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ Testy negatywne z parametryzacj\u0105 (Oldschool)*\n@ParameterizedTest\n@MethodSource(&quot;provideIncorrectUsers&quot;)\npublic void verifyAccountRegistrationWithoutMandatoryFields(\n        User user, String description) {\n    registrationLoginSteps.verifyUserIsNotLoggedIn();\n}\n\nprivate static Stream&lt;Arguments&gt; provideIncorrectUsers() {\n    return Stream.of(\n        Arguments.of(DataProvider.getUserWithoutMandatoryField(), &quot;...&quot;),\n        Arguments.of(DataProvider.getUserWithIncorrectEmail(), &quot;...&quot;),\n        Arguments.of(DataProvider.getUserWithTooShortPassword(), &quot;...&quot;),\n        Arguments.of(DataProvider.getUserWithAlreadyRegisteredEmail(), &quot;...&quot;)\n    );\n}\n<\/pre><\/div>\n\n\n<p><em>* Przyk\u0142ad 1:1<\/em><\/p>\n\n\n\n<p>To ciekawy przyk\u0142ad my\u015blenia o tym, co mo\u017ce p\u00f3j\u015b\u0107 nie tak. AI skupia\u0142o si\u0119 g\u0142\u00f3wnie na happy path. <strong>Stary odruch testerski, kt\u00f3rego modele j\u0119zykowe nie naby\u0142y<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Interfejs zamiast API: \u015bwiadomy kompromis, ale z konsekwencjami<\/strong><\/h3>\n\n\n\n<p>W wi\u0119kszo\u015bci repozytori\u00f3w Oldschool setup danych opiera si\u0119 na UI. To zrozumia\u0142e przy ograniczonym czasie integracja z API wymaga dodatkowej infrastruktury. Jednak koszt tego wyboru jest widoczny w kodzie:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ Setup przez UI (szybki do napisania, kruchy w utrzymaniu)*\n&#x5B;SetUp]\npublic void Setup() {\n    UserIsLoggedIn();\n    _loggedUser.IsUserLoggedIn();\n    UserHasProductsAddedToCart(); \/\/ nawiguje przez UI do produktu\n}\n<\/pre><\/div>\n\n\n<p><em>* Przyk\u0142ad 1:1<\/em><\/p>\n\n\n\n<p>Ka\u017cda zmiana w interfejsie administracyjnym mo\u017ce wywo\u0142a\u0107 efekt domina, k\u0142ad\u0105c nie pojedynczy test, ale ca\u0142y setup. Testy s\u0105 ze sob\u0105 powi\u0105zane i trudne do izolacji. Cho\u0107 pod presj\u0105 czasu taki kompromis jest wybaczalny, w projekcie produkcyjnym trzeba by go pr\u0119dzej czy p\u00f3\u017aniej adresowa\u0107.<\/p>\n\n\n\n<p>Decyzj\u0119 pokrycia tej warstwy podj\u0119\u0142y dwa z pi\u0119ciu zespo\u0142\u00f3w Oldschool. Zespo\u0142y te, mimo ograniczonego czasu, zdecydowa\u0142y si\u0119 zainwestowa\u0107 w setup danych oparty na API, r\u00f3wnolegle do pracy nad warstw\u0105 UI.<\/p>\n\n\n\n<p>W praktyce oznacza\u0142o to podzia\u0142 na specjalizacje, gdzie jedna osoba rozwija\u0142a warstw\u0119 UI, podczas gdy druga budowa\u0142a setup oparty na API. <strong>Efektem by\u0142a wyra\u017anie wy\u017csza jako\u015b\u0107 i stabilno\u015b\u0107 danych testowych. <\/strong>Co istotne, taka decyzja nie by\u0142a naj\u0142atwiejsz\u0105 drog\u0105 \u2013 wymaga\u0142a wi\u0119kszej koordynacji, szczeg\u00f3lnie w obszarze integracji zmian i sp\u00f3jno\u015bci implementacji. Postawienie na stabilno\u015b\u0107 kosztem szybko\u015bci implementacji to \u015bwiadoma decyzja, kt\u00f3ra najlepiej \u015bwiadczy o warsztacie zespo\u0142\u00f3w.<\/p>\n\n\n\n<p><strong>To dow\u00f3d na to, \u017ce in\u017cynierska odpowiedzialno\u015b\u0107 i rozumienie ryzyk wzi\u0119\u0142y g\u00f3r\u0119 nad presj\u0105 czasu<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Stabilno\u015b\u0107 i selektory: Dzia\u0142aj\u0105 lokalnie, a w CI?<\/strong><\/h3>\n\n\n\n<p>W obszarach K3 i K4 pojawia si\u0119 ukryte ryzyko. Cz\u0119\u015b\u0107 zespo\u0142\u00f3w u\u017cywa <em>hardcodowanych wait\u00f3w<\/em> zamiast inteligentnych <em>wait\u00f3w<\/em>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ Hardcode wait (typowe \u017ar\u00f3d\u0142o flakiness)*\nThread.Sleep(1000);\nvar continueButton = DriverProvider.Driver.FindElement(\n    By.Name(&quot;confirmDeliveryOption&quot;));\ncontinueButton.Click();\n\n\/\/ Propozycja: Lepsze podej\u015bcie (czekanie na konkretny stan)\nawait page.click(&#039;#checkout&#039;);\nawait expect(page.locator(&#039;#payment&#039;)).toBeVisible();\n<\/pre><\/div>\n\n\n<p><em>* Przyk\u0142ad 1:1<\/em><\/p>\n\n\n\n<p>Podobnie z selektorami. Zamiast stabilnych atrybut\u00f3w testowych pojawiaj\u0105 si\u0119 kr\u00f3tkie, strukturalnie zale\u017cne <em>selectory<\/em>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ Kruchy selector, zale\u017cno\u015b\u0107 od tre\u015bci przycisku*\nprivate IWebElement cartButton =&gt; DriverProvider.Driver\n    .FindElement(By.XPath(&quot;\/\/a&#x5B;@href=&#039;\/\/145.239.29.97\/cart?action=show&#039;]&quot;));\n\nprivate IWebElement continueShopping =&gt; DriverProvider.Driver\n    .FindElement(By.XPath(&quot;\/\/button&#x5B;@data-dismiss=&#039;modal&#039; and contains(.,&#039;Continue shopping&#039;)]&quot;));\n<\/pre><\/div>\n\n\n<p><em>* Przyk\u0142ad 1:1<\/em><\/p>\n\n\n\n<p>Testy dzia\u0142aj\u0105 lokalnie. Pytanie, jak zachowuj\u0105 si\u0119 przy drobnych zmianach UI lub w wolniejszym \u015brodowisku CI, pozostaje otwarte. W tym przypadku selektor powinien by\u0107 przywi\u0105zany do intencji elementu (co robi), nie do jego reprezentacji (jak wygl\u0105da lub co m\u00f3wi). Zmiana j\u0119zyka interfejsu, \u015brodowiska czy layoutu nie powinna \u0142ama\u0107 testu.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Page Objecty m\u00f3wi\u0105 j\u0119zykiem klikni\u0119\u0107, nie biznesu<\/strong><\/h3>\n\n\n\n<p>Architektura w grupie Oldschool jest poprawna: pojawiaj\u0105 si\u0119 Page Objecty, kod jest czytelny, struktura ma sens. Jednak Page Objecty pe\u0142ni\u0105 g\u0142\u00f3wnie rol\u0119 technicznych <em>wrapper\u00f3w<\/em>, nie warstwy domenowej:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ Wrapper bez logiki domenowej*\n@Step(&quot;Click &#039;Continue&#039; button in Address section&quot;)\npublic void clickContinueButtonInAddressSection() {\n    addressContinueButton.click();\n}\n\n@Step(&quot;Click &#039;Place order&#039; button&quot;)\npublic void clickPlaceOrderButton() {\n    placeOrderButton.click();\n}\n\n\/\/ Propozycja: metoda domenowa \u0142\u0105cz\u0105ca kroki i weryfikuj\u0105ca wynik\npublic Order placeOrder(Product product) {\n    clickContinueButtonInAddressSection();\n    clickContinueButtonInShippingMethodSection();\n    selectCashPaymentRadioButton();\n    acceptTermsAndConditions();\n    clickPlaceOrderButton();\n    return orderConfirmationPage.getOrderDetails(); \/\/ zwraca obiekt domenowy\n}\n<\/pre><\/div>\n\n\n<p><em>* Przyk\u0142ad 1:1<\/em><\/p>\n\n\n\n<p>W pierwszym przypadku test opisuje, jak klikn\u0105\u0107. W drugim sprawdza, jak dzia\u0142a system, co wp\u0142ywa fundamentalnie na warto\u015b\u0107 testu. Zmiana UI (np. nowy krok w checkout) wymaga zmiany tylko w jednym miejscu, a nie we wszystkich testach.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Asercje: fa\u0142szywe poczucie bezpiecze\u0144stwa<\/strong><\/h3>\n\n\n\n<p>Najbardziej powtarzalnym problemem w repozytoriach Oldschool jest jako\u015b\u0107 asercji. Dominuj\u0105 konstrukcje sprawdzaj\u0105ce widoczno\u015b\u0107 lub <em>truthiness<\/em> zamiast konkretnych warto\u015bci biznesowych:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ Asercja sprawdzaj\u0105ca tylko widoczno\u015b\u0107*\nAssert.That(_orderConfirmationPage.ConfirmationMessage);\n\n\/\/ Propozycja: Asercja sprawdzaj\u0105ca warto\u015b\u0107 domenow\u0105\nupdated.StockAvailable.Quantity.Should().Be(updatedQuantity);\nupdated.StockAvailable.ProductId.Should().Be(productId);\n<\/pre><\/div>\n\n\n<p><em>* Przyk\u0142ad 1:1<\/em><\/p>\n\n\n\n<p>Efekt jest paradoksalny: testy przechodz\u0105, wygl\u0105daj\u0105 poprawnie, ale nie chroni\u0105 systemu przed regresj\u0105, <strong>daj\u0105c fa\u0142szywe poczucie bezpiecze\u0144stwa wbudowane w <em>pipeline<\/em><\/strong>.<\/p>\n\n\n\n<p>\u017beby pokaza\u0107 pe\u0142ne spektrum grupy Oldschool: na drugim ko\u0144cu skali znajduje si\u0119 repozytorium, kt\u00f3re zawiera\u0142o jeden plik, niezmodyfikowany szablon wygenerowany przez Playwright CLI, testuj\u0105cy stron\u0119 playwright.dev, nie PrestaShop:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ Jedyny test w repozytorium, domy\u015blny szablon z playwright.dev*\npublic async Task HomepageHasPlaywrightInTitleAndGetStartedLink()\n{\n    await Page.GotoAsync(&quot;https:\/\/playwright.dev&quot;);  \/\/ &lt;-- nie PrestaShop\n    await Expect(Page).ToHaveTitleAsync(new Regex(&quot;Playwright&quot;));\n    var getStarted = Page.Locator(&quot;text=Get Started&quot;);\n    await getStarted.ClickAsync();\n    await Expect(Page).ToHaveURLAsync(new Regex(&quot;.*intro&quot;));\n}\n<\/pre><\/div>\n\n\n<p><em>Przyk\u0142ad 1:1 \u2013 skr\u00f3cona nazwa metody bez wp\u0142ywu na wynik<\/em><\/p>\n\n\n\n<p>Mo\u017ce si\u0119 wydawa\u0107, \u017ce to z\u0142o\u015bliwa obserwacja, jednak jest to jeden z przyk\u0142ad\u00f3w, o kt\u00f3rym m\u00f3wi nasz raport: <strong>bez AI cz\u0119\u015b\u0107 zespo\u0142\u00f3w spala dzie\u0144 na pojedynczym problemie technicznym<\/strong>. Kto\u015b utkn\u0105\u0142 na setupie \u015brodowiska i sze\u015b\u0107 godzin znikn\u0119\u0142o. Dwa zespo\u0142y w tej samej grupie, z wynikami 4,3 i 2,9 &#8211; to jest prawdziwy pokaz rozpi\u0119to\u015bci wynik\u00f3w grupy Oldschool.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Wyj\u0105tek, kt\u00f3ry rz\u0105dzi\u0142 ca\u0142\u0105 grup\u0105<\/strong><\/h3>\n\n\n\n<p>Przy wszystkich tych obserwacjach warto zaznaczy\u0107, \u017ce w grupie Oldschool pojawi\u0142a si\u0119 r\u00f3\u017cnica, kt\u00f3ra nie jest minimalna. Jedno repozytorium (z wynikiem 4,3\/5) <strong>by\u0142o nie tylko najlepszym w grupie Oldschool, ale najlepszym wynikiem w ca\u0142ym badaniu, powy\u017cej wszystkich zespo\u0142\u00f3w AI.<\/strong><\/p>\n\n\n\n<p>To repozytorium <strong>wyr\u00f3\u017cnia\u0142o si\u0119<\/strong> na ka\u017cdym poziomie:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>architektura pi\u0119ciu osobnych projekt\u00f3w (<em>Core<\/em>, <em>Api<\/em>, <em>Ui<\/em>, <em>TestSupport<\/em>, <em>Tests<\/em>),<\/li>\n\n\n\n<li>dedykowany serwis danych,<\/li>\n\n\n\n<li>pe\u0142ny <em>cleanup<\/em> po ka\u017cdym te\u015bcie,<\/li>\n\n\n\n<li>zero sekret\u00f3w w repozytorium.<\/li>\n<\/ul>\n\n\n\n<p>Wr\u00f3cimy do niego szczeg\u00f3\u0142owo przy analizie wzorc\u00f3w.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Czy obecno\u015b\u0107 architekta zrobi\u0142a r\u00f3\u017cnic\u0119?<\/strong><\/h3>\n\n\n\n<p>W obu grupach rozk\u0142ad si\u0142 by\u0142 jednakowy: cztery zespo\u0142y Regular+Regular i jeden z osob\u0105 o znacznie wy\u017cszym do\u015bwiadczeniu.<\/p>\n\n\n\n<p>W grupie Oldschool r\u00f3\u017cnica by\u0142a zauwa\u017calna. Repozytorium z architektem wyr\u00f3\u017cnia\u0142o si\u0119 staranniejsz\u0105 struktur\u0105, przemy\u015blanymi abstrakcjami i dyscyplin\u0105 in\u017cyniersk\u0105 widoczn\u0105 w ka\u017cdym pliku. By\u0142o czu\u0107, \u017ce kto\u015b w zespole wie, jak to powinno wygl\u0105da\u0107.<\/p>\n\n\n\n<p>Ale i tu pojawia si\u0119 kluczowa obserwacja: samo do\u015bwiadczenie, bez wsparcia AI, nie wystarczy\u0142o do zmiany fundamentalnego podej\u015bcia. Presja czasowa sze\u015bciogodzinnego Hackathonu spycha\u0142a wszystkich w kierunku podobnych kompromis\u00f3w.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><em>Do\u015bwiadczenie poprawia jako\u015b\u0107 implementacji. Dopiero AI sprawia, \u017ce do\u015bwiadczenie zaczyna definiowa\u0107 ca\u0142y wynik.<\/em><\/p>\n<\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Grupa AI: Inne podej\u015bcie, te same pu\u0142apki (i jeden paradoks)<\/strong><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Struktura od pierwszego commita<\/strong><\/h3>\n\n\n\n<p>Kiedy otwieramy repozytoria zespo\u0142\u00f3w AI, uderza jedno: wysoki poziom struktury od samego pocz\u0105tku. Testy s\u0105 lepiej nazwane, logicznie pogrupowane i od razu osadzone w architekturze. Nie ma etapu \u201ezacznijmy cokolwiek, potem posprz\u0105tamy\u201d.<\/p>\n\n\n\n<p>Wida\u0107 to w tym, jak wygl\u0105daj\u0105 klasy bazowe, jak zorganizowane s\u0105 <em>fixtures<\/em>, jak konsekwentnie stosowane s\u0105 wzorce.<\/p>\n\n\n\n<p>Por\u00f3wnanie jest uderzaj\u0105ce:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ Oldschool (test zaczyna si\u0119 od szczeg\u00f3\u0142\u00f3w UI)*\npublic void OrderPlacement() {\n    var url = Config&#x5B;&quot;BaseUrl&quot;] + &quot;home-accessories\/7-mug.html&quot;;\n    DriverProvider.Driver.Navigate().GoToUrl(url);\n    _productPage.AddProductToCart();\n    Thread.Sleep(1000);\n    var continueButton = DriverProvider.Driver.FindElement(\n        By.Name(&quot;confirmDeliveryOption&quot;));\n    \/\/ ...\n<\/pre><\/div>\n\n\n<p><em>Przyk\u0142ad \u2013 kompozycja z dw\u00f3ch metod dla zaprezentowania koncepcji<\/em><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ AI (test zaczyna si\u0119 od celu)*\n@Test\n@Description(&quot;End-to-end order: add product, fill checkout, pay, verify&quot;)\nvoid shouldPlaceOrder_whenPayingByBankWire() {\n    open(UIRoutes.HOME);\n    homePage.clickProductByName(EXISTING_PRODUCT);\n    productPage.clickAddToCart();\n    \/\/ ...\n    assertThat(orderConfirmationPage.getOrderReference())\n        .as(&quot;Order reference should be present&quot;)\n        .isNotBlank();\n}\n<\/pre><\/div>\n\n\n<p><em>Przyk\u0142ad 1:1 (skr\u00f3cony)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>AI jako akcelerator architektury<\/strong><\/h3>\n\n\n\n<p>Najwi\u0119kszy skok jako\u015bciowy w grupie AI wida\u0107 w architekturze (K5). Pojawiaj\u0105 si\u0119 warstwy serwisowe, \u015bwiadome <em>fixtures<\/em>, separacja odpowiedzialno\u015bci, czyli rzeczy, kt\u00f3re w Oldschool by\u0142y wyj\u0105tkiem, <strong>tu staj\u0105 si\u0119 standardem<\/strong>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ Fixture z pe\u0142nym lifecycle&#039;em typowe dla grupy AI*\npublic class HybridFixture : TracingFixture {\n    protected UserFactory UserFactory;\n    protected AuthService AuthService;\n\n    &#x5B;SetUp]\n    public async Task SetUpHybridContext() {\n        ApiFactory = new PrestaShopApiFactory(AdminApiContext);\n        UserFactory = new UserFactory(ApiFactory);\n        AuthService = new AuthService(Playwright);\n    }\n\n    &#x5B;TearDown]\n    public async Task TearDownHybridContext() {\n        await ApiFactory.CleanupAsync();\n        await AdminApiContext.DisposeAsync();\n    }\n}\n<\/pre><\/div>\n\n\n<p><em>Przyk\u0142ad 1:1 (skr\u00f3cony)<\/em><\/p>\n\n\n\n<p>AI pozwala zespo\u0142om bardzo szybko wej\u015b\u0107 na poziom, kt\u00f3ry normalnie wymaga czasu i wielu iteracji projektowych. Skraca drog\u0119 od \u201eu mnie dzia\u0142a\u201d do \u201ejest zdefiniowane\u201d.<\/p>\n\n\n\n<p><strong>Ale tu pojawia si\u0119 te\u017c pierwszy problem.<\/strong> Cz\u0119\u015b\u0107 tej architektury jest poprawna formalnie, lecz p\u0142ytka funkcjonalnie, generuj\u0105c struktury, kt\u00f3re wygl\u0105daj\u0105 profesjonalnie, ale bez \u015bwiadomego <em>human-in-the-loop<\/em> nie s\u0142u\u017c\u0105 niczemu konkretnemu.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Asercje: Ta sama pi\u0119ta achillesowa co w Oldschool<\/strong><\/h3>\n\n\n\n<p>Mimo lepszej struktury jeden problem pozostaje niemal niezmieniony: g\u0142\u0119boko\u015b\u0107 walidacji biznesowej. Nawet w najlepszych repozytoriach AI asercje s\u0105 cz\u0119sto zbyt og\u00f3lne:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ Asercja, kt\u00f3ra potwierdza, \u017ce co\u015b istnieje*\nassertNotNull(actual.getId(), &quot;Customer ID should not be null&quot;);\nassertNotNull(actual.getId(), &quot;New customer ID should be returned&quot;);\n\n\/\/ Propozycja: Asercja, kt\u00f3ra potwierdza, \u017ce dzia\u0142a poprawnie\nassertThat(orderConfirmationPage.getOrderReference())\n    .isNotBlank();\nassertThat(displayedPrice).isEqualByComparingTo(expectedGrossPrice);\n<\/pre><\/div>\n\n\n<p><em>Przyk\u0142ad 1:1<\/em><\/p>\n\n\n\n<p>Jeden z zespo\u0142\u00f3w AI poszed\u0142 dalej i zbudowa\u0142 dedykowan\u0105 klas\u0119 <em>PriceUtils<\/em> do weryfikacji warto\u015bci brutto po zastosowaniu VAT. To rzadki przyk\u0142ad asercji na poziomie logiki biznesowej w tej grupie.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><em>AI poprawia spos\u00f3b pisania test\u00f3w, ale nie wymusza tego, co testy powinny sprawdza\u0107.<\/em><\/p>\n<\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Dane testowe i niespodzianka z sekretami<\/strong><\/h3>\n\n\n\n<p>W obszarze danych testowych (K2) zespo\u0142y AI robi\u0105 krok naprz\u00f3d: pojawia si\u0119 API setup, my\u015blenie o izolacji, unikalne dane generowane przez <em>factory<\/em>. Ale konsekwencja bywa zaburzona \u2013 w jednym pliku widzimy wzorcowe podej\u015bcie, natomiast kilka plik\u00f3w dalej wy\u0142ania si\u0119 setup przez UI.<\/p>\n\n\n\n<p><strong>Jest te\u017c obszar, gdzie grupa AI wypad\u0142a gorzej ni\u017c Oldschool<\/strong>: bezpiecze\u0144stwo sekret\u00f3w. Dwa repozytoria AI mia\u0142y API key bezpo\u015brednio w plikach konfiguracyjnych <em>zacommitowanych<\/em> do <em>repo<\/em>. Jedno z nich zawiera\u0142o przy tym komentarz:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ Obrazowy przyk\u0142ad sekret\u00f3w*\n# Ideally, this should be stored in secrets\n# but let&#039;s keep it here for simplification\napi.key= tutaj nale\u017cy wpisa\u0107 API\nadmin.password=to miejsce na wpisanie has\u0142a\n<\/pre><\/div>\n\n\n<p><em>* Przyk\u0142ad 1:1 (z usuni\u0119tymi danymi wra\u017cliwymi)<\/em><\/p>\n\n\n\n<p>Zespo\u0142y Oldschool radzi\u0142y sobie z tym lepiej, brak sekret\u00f3w w repo by\u0142 tam norm\u0105 (lata do\u015bwiadczenia?). <strong>To pokazuje, \u017ce AI przyspiesza implementacj\u0119, ale nie zast\u0119puje \u015bwiadomo\u015bci in\u017cynierskiej w ka\u017cdym obszarze.<\/strong><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Cztery wzorce w grupie AI<\/strong><\/h2>\n\n\n\n<p>Analizuj\u0105c pi\u0119\u0107 repozytori\u00f3w AI, wida\u0107 wyra\u017anie, \u017ce nie tworz\u0105 jednorodnej grupy. Wy\u0142aniaj\u0105 si\u0119 cztery r\u00f3\u017cne wzorce, kt\u00f3re nazwa\u0142bym:<\/p>\n\n\n\n<p><strong>1. \u201eFabryka test\u00f3w\u201d<\/strong> \u2013 imponuj\u0105ca liczba test\u00f3w (blisko 200), testy hybrydowe API+UI, <em>fixtures <\/em>z <em>cleanup<\/em>. Najwi\u0119kszy wolumen w ca\u0142ym badaniu. S\u0142abo\u015b\u0107: sekrety w <em>repo <\/em>i miejscami p\u0142ytkie asercje (<em>ToContainTextAsync<\/em> zamiast weryfikacji warto\u015bci) oraz testy API ograniczone do <em>Statuscode 200<\/em>.<\/p>\n\n\n\n<p><strong>2. \u201eSolidny rzemie\u015blnik\u201d<\/strong> \u2013 37 test\u00f3w, Allure, dedykowana klasa <em>PriceUtils<\/em> do weryfikacji VAT, asercje na konkretne warto\u015bci. Najlepsza \u015brednia jako\u015bciowa w grupie AI. Brak API do setupu danych, czyli rejestracja odbywa si\u0119 przez UI, co jest \u015bwiadomym uproszczeniem.<\/p>\n\n\n\n<p><strong>Ciekawostka: <\/strong>Zesp\u00f3\u0142 ten boryka\u0142 si\u0119 z obs\u0142u\u017ceniem wspomnianych w oryginalnym raporcie selektor\u00f3w dla dynamicznych przycisk\u00f3w. To przepali\u0142o cz\u0119\u015b\u0107 zadanego czasu, przez co wymaga\u0142o pewnych po\u015bwi\u0119ce\u0144 w pokryciu. Nie by\u0142 w tym jednak odosobniony \u2013 wzorzec ten cz\u0119sto wraca\u0142 w zespo\u0142ach AI.<\/p>\n\n\n\n<p><strong>3. \u201eSzeroki zasi\u0119g\u201d<\/strong> \u2013 60 test\u00f3w API pokrywaj\u0105cych kupony, waluty, promocje, katalog. Szeroki zakres, ale asercje miejscami operuj\u0105 na surowym JSON zamiast na deserializowanych obiektach.<\/p>\n\n\n\n<p><strong>Przyk\u0142ad:<\/strong> zamiast deserializowa\u0107 odpowied\u017a i sprawdza\u0107 w\u0142a\u015bciwo\u015b\u0107 obiektu, test por\u00f3wnuje fragment surowego stringa:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ Asercja na surowym JSON (krucha i nieczytelna)*\nAssert.That(body, Does.Contain(&quot;\\&quot;gift_product\\&quot;:\\&quot;11\\&quot;&quot;).Or.Contain(&quot;\\&quot;gift_product\\&quot;:11&quot;),\nAssert.That(body, Does.Contain(&quot;\\&quot;minimum_amount\\&quot;:\\&quot;80&quot;).Or.Contain(&quot;\\&quot;minimum_amount\\&quot;:80&quot;),\nAssert.That(body, Does.Contain(&quot;\\&quot;active\\&quot;:\\&quot;1\\&quot;&quot;).Or.Contain(&quot;\\&quot;active\\&quot;:1&quot;),\n\n\/\/ Propozycja: deserializacja i asercja na w\u0142a\u015bciwo\u015bci\nvar coupon = JsonSerializer.Deserialize&lt;CartRule&gt;(body);\nAssert.That(coupon.Active, Is.True);\nAssert.That(coupon.ReductionAmount, Is.EqualTo(5.0m));\n<\/pre><\/div>\n\n\n<p>* <em>Przyk\u0142ad 1:1<\/em><\/p>\n\n\n\n<p>Taka asercja przejdzie, nawet je\u015bli format JSON si\u0119 zmieni, bo szuka <em>patternu<\/em> w <em>stringu<\/em>, nie weryfikuje warto\u015bci domenowej. Co ciekawe, przyk\u0142ad pokazuje, \u017ce zesp\u00f3\u0142 by\u0142 na tyle \u015bwiadomy problemu, \u017ce w wielu miejscach dodaje <em>.Or.Contain(&#8230;)<\/em> z alternatywn\u0105 wersj\u0105 bez cudzys\u0142ow\u00f3w. To nie rozwi\u0105zuje problemu, ale pokazuje, \u017ce kto\u015b zdawa\u0142 sobie spraw\u0119 z krucho\u015bci.<\/p>\n\n\n\n<p><strong>4. \u201eDokumentacja zamiast kodu\u201d<\/strong> \u2013 imponuj\u0105ce artefakty: plany test\u00f3w w .claude\/, self-evaluation po ka\u017cdym kryterium K1-K8, szczeg\u00f3\u0142owe scenariusze TC-001 do TC-030. Ale 5 test\u00f3w w repozytorium. AI \u015bwietnie poradzi\u0142o sobie z planowaniem \u2013 niestety, czas sko\u0144czy\u0142 si\u0119 zanim przysz\u0142o do implementacji.<\/p>\n\n\n\n<p><strong>Uwaga: <\/strong>to nie jest wzorzec nieudany, ale ostrze\u017cenie dla ca\u0142ej bran\u017cy. AI by\u0142o tak dobre w planowaniu, \u017ce zesp\u00f3\u0142 sp\u0119dzi\u0142 wi\u0119kszo\u015b\u0107 czasu na budowaniu mapy zamiast i\u015b\u0107 w teren. To ciekawe zjawisko, gdzie AI generuje tak przekonuj\u0105ce artefakty planistyczne, \u017ce implementacja schodzi na drugi plan.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Paradoks tego badania: najlepsze repozytorium pochodzi z grupy Oldschool<\/strong><\/h2>\n\n\n\n<p>Tu dochodzimy do najwa\u017cniejszego odkrycia ca\u0142ej analizy i do miejsca, w kt\u00f3rym proste narracje o AI musz\u0105 ust\u0105pi\u0107 faktom.<\/p>\n\n\n\n<p><strong>Najlepsze repozytorium w ca\u0142ym badaniu (z wynikiem 4,3\/5) pochodzi z grupy Oldschool<\/strong>. Pobi\u0142o wszystkie pi\u0119\u0107 repozytori\u00f3w AI. I jest dok\u0142adnie tym, co artyku\u0142 o grupie AI opisywa\u0142 jako niedo\u015bcig\u0142y wzorzec: <strong>API jako podstawa danych, testy hybrydowe, pe\u0142ny cleanup, walidacja domenowa<\/strong>.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ Wzorcowy setup danych przez API z grupy Oldschool*\npublic CreatedProduct CreateProductWithQuantity(\n    int quantity = TestDataConstants.Product.DefaultAvailableQuantity) {\n    CreateProductRequest request = CreateProductRequestFactory.CreateValid(settings);\n    ProductEnvelope response = productsApi.CreateProduct(request);\n    var productId = response.Product.Id\n        ?? throw new InvalidOperationException(&quot;Product id not returned&quot;);\n    cleanupTracker.Track(productId, productsApi);  \/\/ automatyczny cleanup\n    stockAvailablesApi.UpdateQuantity(stockAvailableId, quantity);\n    return new CreatedProduct { Request = request, Response = response };\n}\n<\/pre><\/div>\n\n\n<p><em>* Przyk\u0142ad \u2013 kompozycja metod dla zaprezentowania koncepcji<\/em><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ Asercje na warto\u015bci domenowe z grupy Oldschool*\nAt&lt;CartPopupPage&gt;(x =&gt; {\n    x.ProductName.Should().Be(product.Name);\n    x.ProductQuantity.Should().Be(&quot;1&quot;);\n});\n\nupdated.StockAvailable.Quantity.Should().Be(updatedQuantity);\nupdated.StockAvailable.ProductId.Should().Be(productId);\n\n<\/pre><\/div>\n\n\n<p><em>* Przyk\u0142ad \u2013 kompozycja metod dla zaprezentowania koncepcji<\/em><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ ResourceCleanupTracker - automatyczne sprz\u0105tanie po testach*\npublic class ResourceCleanupTracker {\n    public void Cleanup() {\n        foreach (var item in _resources.DistinctBy(x =&gt; (x.Id, x.Api)).ToList())\n            TryDelete(() =&gt; item.Api.DeleteById(item.Id));\n    }\n}\n<\/pre><\/div>\n\n\n<p><em>* Przyk\u0142ad 1:1 z uproszczeniem w postaci var item \u2013 r\u00f3\u017cnica jedynie stylistyczna<\/em><\/p>\n\n\n\n<p>Pi\u0119\u0107 osobnych projekt\u00f3w (<em>Core<\/em>, <em>Api<\/em>, <em>Ui<\/em>, <em>TestSupport<\/em>, <em>Tests<\/em>), dedykowany generator danych z GUID-em w ka\u017cdym e-mailu, konfiguracja przez <em>User Secrets<\/em> bez ani jednego sekretu w repo, automatyczne screenshoty przy failach.<\/p>\n\n\n\n<p>To opis najlepszego repozytorium w ca\u0142ym badaniu (napisanego bez AI), przez zesp\u00f3\u0142 z architektem, w sze\u015b\u0107 godzin. Mo\u017cna wi\u0119c wysnu\u0107 nast\u0119puj\u0105cy wniosek:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><em>AI podnosi poziom wej\u015bcia dla wszystkich, ale szczyt nadal nale\u017cy do do\u015bwiadczenia.<\/em><\/p>\n<\/blockquote>\n\n\n\n<p>Warto zatrzyma\u0107 si\u0119 przy zestawieniu, kt\u00f3re wynika z danych: 196 test\u00f3w, 3,6\/5 vs 8 test\u00f3w, 4,3\/5. Artyku\u0142 to opisuje, ale <strong>warto powiedzie\u0107 wprost<\/strong>: 8 test\u00f3w, kt\u00f3re weryfikuj\u0105 konkretne warto\u015bci domenowe, sprz\u0105taj\u0105 po sobie i izoluj\u0105 dane, jest prawdopodobnie bardziej warto\u015bciowe produkcyjnie ni\u017c 196 test\u00f3w z p\u0142ytkimi asercjami. <strong>Du\u017ca liczba test\u00f3w bez jako\u015bci daje fa\u0142szywsze poczucie bezpiecze\u0144stwa ni\u017c ma\u0142a liczba dobrych test\u00f3w<\/strong>. To wniosek, kt\u00f3ry mened\u017cerowie i tech leaderzy powinni zabra\u0107 z tego badania: <strong><em>coverage<\/em> to nie licznik, a kryterium jako\u015bciowe<\/strong>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Gdzie do\u015bwiadczenie naprawd\u0119 ma znaczenie<\/strong><\/h2>\n\n\n\n<p>Tu pojawia si\u0119 g\u0142\u00f3wny wniosek dotycz\u0105cy roli do\u015bwiadczenia. Nale\u017cy jednocze\u015bnie zaznaczy\u0107, \u017ce jest bardziej subtelny ni\u017c s\u0142yszane w mediach \u201eAI zast\u0119puje do\u015bwiadczenie\u201d czy \u201edo\u015bwiadczenie zawsze wygrywa\u201d.<\/p>\n\n\n\n<p>W grupie Oldschool r\u00f3\u017cnica mi\u0119dzy zespo\u0142ami Regular+Regular a Architect+Junior by\u0142a widoczna, ale presja czasowa sp\u0142aszcza\u0142a wyniki. Wszyscy zmierzali w podobnym kierunku, a kompromisy czasowe by\u0142y zbli\u017cone.<\/p>\n\n\n\n<p>W grupie AI ta r\u00f3\u017cnica sta\u0142a si\u0119 decyduj\u0105ca. AI usun\u0119\u0142o bariery techniczne: sk\u0142adni\u0119, <em>setup frameworka<\/em>, podstawowe wzorce. Okaza\u0142o si\u0119, \u017ce kiedy te bariery znikaj\u0105, to co pozostaje, to czyste decyzje architektoniczne (proporcjonalne do do\u015bwiadczenia).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Trzy obszary, gdzie do\u015bwiadczenie (za)decyduje<\/strong><\/h2>\n\n\n\n<p><strong>1. Co testujemy, a nie jak testujemy<\/strong> \u2013 wi\u0119kszo\u015b\u0107 zespo\u0142\u00f3w Oldschool i AI zatrzyma\u0142a si\u0119 na weryfikacji widoczno\u015bci komunikat\u00f3w. Najlepsze repozytoria z obu grup posz\u0142y dalej: weryfikowa\u0142y konkretne warto\u015bci domenowe, poprawno\u015b\u0107 oblicze\u0144 VAT, izolacj\u0119 koszyk\u00f3w mi\u0119dzy u\u017cytkownikami.<\/p>\n\n\n\n<p>Pokazuje to nie r\u00f3\u017cnic\u0119 w umiej\u0119tno\u015bci pisania kodu, a w \u015bwiadomym rozplanowaniu, czemu te testy w og\u00f3le s\u0142u\u017c\u0105.<\/p>\n\n\n\n<p><strong>2. Strategia danych testowych<\/strong> \u2013 ka\u017cdy zesp\u00f3\u0142, kt\u00f3ry podj\u0105\u0142 \u015bwiadom\u0105 decyzj\u0119 o API jako warstwie setupu, natychmiast skoczy\u0142 o poziom jako\u015bci. Nie chodzi tylko o szybko\u015b\u0107, ale o izolacj\u0119 test\u00f3w, deterministyczne dane, mo\u017cliwo\u015b\u0107 r\u00f3wnoleg\u0142ego uruchamiania. Niezale\u017cnie od sk\u0142adu, jest to efekt do\u015bwiadczenia zdobytego tward\u0105 praktyk\u0105 (a wi\u0119c nie wynika stricte z promptowania AI, ale z rozumienia, dlaczego izolacja danych w testach ma znaczenie).<\/p>\n\n\n\n<p><strong>3. My\u015blenie systemowe, a zbi\u00f3r test\u00f3w<\/strong> \u2013 wi\u0119kszo\u015b\u0107 repozytori\u00f3w to zbi\u00f3r test\u00f3w. Najlepsze to systemy testowe. R\u00f3\u017cnica le\u017cy w tym, czy architektura pozwala na skalowanie, czy <em>cleanup<\/em> jest automatyczny, czy warstwy odpowiedzialno\u015bci s\u0105 rozdzielone. AI mo\u017ce pom\u00f3c szybko zbudowa\u0107 poszczeg\u00f3lne elementy tego systemu, ale decyzja o tym, \u017ce system ma w og\u00f3le istnie\u0107 to ludzka decyzja architektoniczna.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Co AI robi naprawd\u0119 dobrze (i gdzie nie dowozi)<\/strong><\/h2>\n\n\n\n<p>\u017beby nie by\u0142o w\u0105tpliwo\u015bci: AI wnosi ogromn\u0105, mierzaln\u0105 warto\u015b\u0107. W naszym badaniu r\u00f3\u017cnica w liczbie test\u00f3w by\u0142a uderzaj\u0105ca \u2013 grupy AI dostarczy\u0142y od 5 do niemal 200 test\u00f3w, Oldschool od 5 do 8. Skr\u00f3cenie czasu wej\u015bcia na dobry poziom jest realne.<\/p>\n\n\n\n<p><strong>AI naprawd\u0119 pomaga w:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Szybkim wej\u015bciu na poziom, kt\u00f3ry Oldschool osi\u0105ga po wielu iteracjach.<\/li>\n\n\n\n<li>Redukcji b\u0142\u0119d\u00f3w implementacyjnych i <em>antypattern\u00f3w.<\/em><\/li>\n\n\n\n<li>Przyspieszeniu wychodzenia z blokad technicznych.<\/li>\n\n\n\n<li>Budowaniu struktury projektu od pierwszego <em>commita.<\/em><\/li>\n\n\n\n<li>Generowaniu du\u017cej liczby scenariuszy testowych w kr\u00f3tkim czasie.<\/li>\n<\/ul>\n\n\n\n<p><strong>AI konsekwentnie nie dowozi w:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>G\u0142\u0119boko\u015bci walidacji biznesowej \u2013 nie zapyta, czy sprawdzi\u0142e\u015b VAT.<\/li>\n\n\n\n<li>Strategii danych \u2013 nie zadecyduje, \u017ce setup powinien by\u0107 przez API.<\/li>\n\n\n\n<li>Bezpiecze\u0144stwie \u2013 nie przeszkodzi <em>zacommitowa\u0107<\/em> sekret\u00f3w do <em>repo.<\/em><\/li>\n\n\n\n<li>My\u015bleniu systemowym \u2013 generuje testy, nie systemy testowe.<\/li>\n\n\n\n<li>Pragmatyzmie \u2013 cz\u0119sto generuje \u201e\u0142adny\u201d kod bez realnej warto\u015bci.<\/li>\n\n\n\n<li>Testach negatywnych \u2013 skupia si\u0119 na happy path, pomijaj\u0105c przypadki brzegowe i b\u0142\u0119dne dane.<\/li>\n<\/ul>\n\n\n<div class=\"nsw-o-blogersii-banner\">\n            <picture>\n            <source srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2026\/04\/Blog-Testing-Lab-Desktop_.jpg\" media=\"(min-width: 992px)\" >\n            <source srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2026\/04\/Blog-Testing-Lab-Mob_.jpg\" media=\"(min-width: 300px)\" >            <img decoding=\"async\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2026\/04\/Blog-Testing-Lab-Desktop_.jpg\" alt=\"\"  class=\"\"  >\n        <\/picture>\n        <div class=\"cnt\">\n                    <div class=\"nsw-m-title-block -h3 -invert  -has-title-margin-bottom-0 -has-title-font-weight-bold\">\n                                <h2 class=\"nsw-m-title-block__title\">Testing &#038; QA<\/h2>\n                <\/div>\n                            <p class=\"has-nsw-p-4-font-size has-invert-color\">\n                Zapewnij jako\u015b\u0107, wydajno\u015b\u0107 i bezpiecze\u0144stwo swojego oprogramowania dzi\u0119ki naszym us\u0142ugom testowania i automatyzacji test\u00f3w.\n            <\/p>\n                            <a  href=\"https:\/\/sii.pl\/oferta\/testing-qa\/\" class=\"nsw-a-button -ghost -banner-button\"   >\n        <span>Poznaj ofert\u0119<\/span>\n    <\/a>\n            <\/div>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Najwa\u017cniejszy wniosek<\/strong><\/h2>\n\n\n\n<p>To badanie mia\u0142o jeden wyra\u017any paradoks: repozytorium, kt\u00f3re wszyscy traktowali jako wzorzec dla grupy AI: API setup, hybryda, <em>cleanup<\/em>, walidacja domenowa \u2013 <strong>nale\u017ca\u0142o do grupy Oldschool<\/strong>.<\/p>\n\n\n\n<p>Ten paradoks m\u00f3wi nam co\u015b istotnego. AI dramatycznie obni\u017ca pr\u00f3g wej\u015bcia. Sprawia, \u017ce ka\u017cdy mo\u017ce szybko pisa\u0107 ustrukturyzowany, poprawny kod. To prawdziwa zmiana.<\/p>\n\n\n\n<p>Ale jednocze\u015bnie gdy bariery techniczne znikaj\u0105, uwypukla si\u0119 to, co zawsze decydowa\u0142o o jako\u015bci: rozumienie domeny, my\u015blenie architektoniczne, wiedza o tym, co warto testowa\u0107 i dlaczego.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><em>AI znacz\u0105co poprawia spos\u00f3b, w jaki piszemy testy, ale nie poprawia tego, co testujemy.<\/em><\/p>\n<\/blockquote>\n\n\n\n<p>Dla zespo\u0142\u00f3w oznacza to konkretne wnioski:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Je\u015bli nie u\u017cywasz AI<\/strong> \u2013 tracisz na produktywno\u015bci. Tempo pracy b\u0119dzie wolniejsze, a liczba dostarczanych scenariuszy ni\u017csza.<\/li>\n\n\n\n<li><strong>Je\u015bli u\u017cywasz AI bez zmiany podej\u015bcia<\/strong> \u2013 b\u0119dziesz mie\u0107 \u0142adniejszy kod, ale testy nadal b\u0119d\u0105 sprawdza\u0107 przep\u0142yw, nie logik\u0119 biznesow\u0105.<\/li>\n\n\n\n<li><strong>Je\u015bli \u0142\u0105czysz AI z do\u015bwiadczeniem architektonicznym<\/strong> \u2013 mo\u017cesz szybciej zbudowa\u0107 system testowy, kt\u00f3ry faktycznie chroni produkt.<\/li>\n<\/ul>\n\n\n\n<p>Najwi\u0119kszym ryzykiem po tym Hackathonie jest proste za\u0142o\u017cenie: \u201eSkoro mamy AI, jako\u015b\u0107 sama si\u0119 poprawi\u201d. Nie poprawi. AI nie zna Twojej domeny, nie rozumie Twojego systemu, nie podejmie za Ciebie decyzji o tym, co warto weryfikowa\u0107.<\/p>\n\n\n\n<p>Mo\u017ce Ci pom\u00f3c szybciej doj\u015b\u0107 do rozwi\u0105zania. Ale to Ty musisz wiedzie\u0107, dok\u0105d idziesz.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><em>AI obni\u017ca poziom wej\u015bcia, ale jednocze\u015bnie podnosi znaczenie do\u015bwiadczenia na poziomie decyzji.<\/em><\/p>\n<\/blockquote>\n\n\n\n<p>To badanie pokazuje nam tera\u017aniejszo\u015b\u0107, do kt\u00f3rej cz\u0119\u015b\u0107 zespo\u0142\u00f3w jeszcze nie dotar\u0142a.<\/p>\n\n\n\n<p>Automatyzacja test\u00f3w bez u\u017cycia AI sta\u0142a si\u0119 podej\u015bciem wolniejszym i coraz trudniejszym do uzasadnienia. Podobnie jak testy manualne nie znikn\u0119\u0142y po pojawieniu si\u0119 automatyzacji (ale zmieni\u0142y swoj\u0105 rol\u0119 i status), tak klasyczna automatyzacja staje si\u0119 nowym podej\u015bciem manualnym. Wci\u0105\u017c potrzebna, wci\u0105\u017c warto\u015bciowa w odpowiednich kontekstach, ale przestaje by\u0107 domy\u015blnym wyborem dla kogo\u015b, kto chce pracowa\u0107 efektywniej.<\/p>\n\n\n\n<p>Pytanie wi\u0119c nie brzmi \u201eCzy warto u\u017cywa\u0107 AI w automatyzacji\u201d, a \u201eJak szybko Tw\u00f3j zesp\u00f3\u0142 jest w stanie zmieni\u0107 spos\u00f3b my\u015blenia o tej pracy\u201d, bo narz\u0119dzia ju\u017c s\u0105. Czekaj\u0105 na do\u015bwiadczonych ekspert\u00f3w, kt\u00f3rzy b\u0119d\u0105 wiedzie\u0107, co z nimi zbudowa\u0107.<\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;33710&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;3&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;2&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;5\\\/5&quot;,&quot;size&quot;:&quot;30&quot;,&quot;title&quot;:&quot;Jak naprawd\u0119 wygl\u0105da kod z Sii Testing Lab? Otwieramy repozytoria&quot;,&quot;width&quot;:&quot;159&quot;,&quot;_legend&quot;:&quot;{score}\\\/5&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 2px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 30px; height: 30px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 2px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 30px; height: 30px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 2px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 30px; height: 30px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 2px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 30px; height: 30px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 2px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 30px; height: 30px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 159px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 2px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 30px; height: 30px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 2px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 30px; height: 30px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 2px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 30px; height: 30px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 2px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 30px; height: 30px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 2px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 30px; height: 30px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 24px;\">\n            5\/5    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>W badaniu Sii Testing Lab opisali\u015bmy siedem kluczowych wniosk\u00f3w z naszego Hackathonu po\u015bwi\u0119conego roli AI w automatyzacji test\u00f3w. Publikacja spotka\u0142a &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/jak-naprawde-wyglada-kod-z-sii-testing-lab-otwieramy-repozytoria\/\">Continued<\/a><\/p>\n","protected":false},"author":177,"featured_media":33711,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1317],"tags":[682,103,1032,868,146],"class_list":["post-33710","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-testowanie","tag-artificial-intelligence","tag-autoamtyzacja-testow","tag-case-study","tag-hackathon","tag-testing"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2026\/04\/Hackathon-1.jpg","category_names":["Testowanie"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/33710"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/177"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=33710"}],"version-history":[{"count":1,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/33710\/revisions"}],"predecessor-version":[{"id":33713,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/33710\/revisions\/33713"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/33711"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=33710"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=33710"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=33710"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}