Odczytanie rzuconego wyjątku z CMD za pomocą ProcessBuilder.

Odczytanie rzuconego wyjątku z CMD za pomocą ProcessBuilder.
NO
  • Rejestracja:ponad 3 lata
  • Ostatnio:ponad 3 lata
  • Postów:6
0

Cześć! Testuję aplikację konsolową, która pobiera wzór String jako pierwszy parametr oraz kolejny ciąg znaków String jako drugi parametr i sprawdza czy wzór znajduje się w ciągu oraz po którym znaku z ciągu występuje.
Testuję z użyciem JUnit, Cucumber i Gherkin.

Chcę przetestować, że aplikacja rzuci ArrayIndexOutOfBoundsException w momencie gdy pierwszy, drugi lub obydwa parametry są puste. Jak dotąd najbardziej sensowną metodą na to wydaje mi się, otworzenie CMD za pomocą ProcessBuilder, tam podanie ścieżki do aplikacji oraz podanie parametrów. Ta część działa, faktycznie otwiera mi się okno konsoli i widzę, że wyjątek jest rzucony. Jednak chcę to potwierdzić za pomocą asercji, a żeby to zrobić potrzebuję odczytać wyjątek z konsoli z pomocy metody testowej w moim step definition. No i tutaj rodzi się problem, czy coś takiego jest w ogóle możliwe, a jeśli tak to w jaki sposób mogę to zrobić? Wydaje mi się, że powinienem kombinować z getInputStream() / getOutputStream() z klasy Process niestety zupełnie nie mam pomysłu jak to zrobić. Poniżej moje metody @Given i @When ze step definition. Sama asercja wyjątku planowana jest w metodzie @Then.

Kopiuj
@Given("Parameters list is empty.")
    public void parametersListIsEmpty() {
        args = new String[2];
        args[0] = " ";
        args[1] = " ";

        stringBuilder = new StringBuilder();
        stringBuilder.append("\" java PatternSearch.java ");
        stringBuilder.append(args[0]);
        stringBuilder.append(" ");
        stringBuilder.append(args[1]);
        stringBuilder.append("\"");
    }

    @When("App is run with invalid parameters")
    public void appIsRunWithInvalidParameters() {
        String filePath = FileSystems.getDefault().getPath("./"
                + "\\src\\main\\java\\com\\sample\\textsearch\\").toAbsolutePath().toString();
        String command = stringBuilder.toString();
        String[] processCommand = {"cmd.exe", "/c", "start", "cmd.exe", "/k", command};

        System.out.println(filePath);

        File log = null;

        try {
            ProcessBuilder proBuilder = new ProcessBuilder(processCommand);
            proBuilder.directory(new File(filePath));
            proBuilder.inheritIO();

            log = new File("CMDOutput.txt");

            proBuilder.redirectErrorStream(true);
            proBuilder.redirectOutput(ProcessBuilder.Redirect.appendTo(log));

            Process process = proBuilder.start();

            //one attempt to see CMD output
            String output = new String(process.getInputStream().readAllBytes());
            System.out.println(output);

            //another attempt to see CMD output
            System.out.println(processOutput(process));

        } catch (IOException e) {
            e.printStackTrace();
            excMessage = e.getMessage();
            System.out.println(excMessage);
        }
    }

    public String processOutput(Process process) {
         String output = null;

        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            output = reader.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return output;
    }

ProcessBuilder i Process to na razie dla mnie czarna magia. Mój kod tworzy jeden proces cmd.exe i w nim dopiero drugi taki proces wraz ze ścieżką do aplikacji oraz komendą, domyślam się więc, że potrzebuję wyłuskać output z tego drugiego procesu.
Z góry ogromnie dziękuję za jakiekolwiek wskazówki.

AK
  • Rejestracja:ponad 6 lat
  • Ostatnio:4 dni
  • Postów:3561
0

Aplikacji się (ZTCW) nie testuje. W ogóle trudno mówić o testowaniu czegoś, co być może - nie znamy wnętrza "czarnej skrzynki" jest proceduralnym spagetti (mam na myśli, ze potrafię szanować DOBRE programowanie strukturalne)

testuje się np metody KLASY, która to klasa może stanowić 98% aplikacji, ale to jednak coś innego.
Wystarczy, że będziesz myślał kategoriami "lightweight main", czyli taki mający jedną, góra dwie linijki.

Podobnie, jak nie będziesz testował loadera JAR-a z twoim main'em itd - a od tego, jak od setki innych powodów, zależy przechodzenie wyjątku zabijającego do środowiska


Bo C to najlepszy język, każdy uczeń ci to powie
NO
  • Rejestracja:ponad 3 lata
  • Ostatnio:ponad 3 lata
  • Postów:6
0

@AnyKtokolwiek: Napisałem "aplikacja" ponieważ całość mieści się w jednej klasie. Jeśli dobrze rozumiem, sugerujesz w ogóle nie testować takiego przypadku? Chciałem po prostu przetestować możliwe najwięcej scenariuszy.

Biorąc pod uwagę, że testuję z użyciem Cucumber czyli BDD, postanowiłem testować tę aplikację end-to-end. W ogóle nie testuję pojedynczych metod ponieważ jak rozumiem nie na tym polega BDD i chodzi właśnie o przetestowania zachowania całej aplikacji/klasy. Z tego też względu wydawało mi się, że rzucenie wyjątku (czyli zakończenie działania aplikacji) jest jednym z zachowań, w przypadku gdy nie podamy danych wejściowych.

Nie ukrywam, że dopiero zaczynam się uczyć BDD i o ile składania jest banalna to mam trochę problem z określeniem co powinno zostać przetestowane, a co zostawić dla testów jednostkowych.

Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

Proces który odpalasz to cmd.exe i on działa ok. Trzeba by odpalić bezpośrednio to co odpalasz, żeby móc sensownie z tym pracować. Niemniej powinno się dać odczytać stdout stderr z tego procesu i coś wyłuskać z outputu, jeśli ta twoja aplikacja w ogóle wypisuje jakieś komunikaty błędów.

Niemniej może prościej byłoby w teście zwyczajnie zawołać main() z tymi parametrami? ;)


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 1x, ostatnio: Shalom
AK
  • Rejestracja:ponad 6 lat
  • Ostatnio:4 dni
  • Postów:3561
0
Shalom napisał(a):

Niemniej może prościej byłoby w teście zwyczajnie zawołać main() z tymi parametrami? ;)

Dokładnie to chciałem powiedzieć ... prawie ... bo w moim marzeniu main() jest tak minimalny, że niemal zerowy

testowanie całego runtimu windowsa / pokoleń loaderów javy / antywirusów / ustawienia terminala / h wie czego jeszcze ... to mam mały sens. Coś wykaże na czerwono lub zielono, ale co naprawdę?


Bo C to najlepszy język, każdy uczeń ci to powie
edytowany 1x, ostatnio: AnyKtokolwiek
AK
Pamiętacie wylot części softu koło wersji 6 / 7 gdy string copyright się zmienił z Suna na Oracle'a (ze sporym zresztą opóźnieniem w stosunku do biznesowego czasu rzeczywistego) ? Problem? Na pewno. Czyj błąd ...
KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:9 dni
  • Lokalizacja:Silesia/Marki
  • Postów:5505
2
AnyKtokolwiek napisał(a):

Aplikacji się (ZTCW) nie testuje.

Testuje się. Nie raz stawiałem całą aplikację webową żeby uderzać w testach po prawdziwym http :)
W przypadku aplikacji konsolowych jest to na pewno rzadsze (ale aplikacje konsolowe rzadziej się pisze w Javie) i trudniejsze (interfejs CLI jest różny między systemami, w przeciwieństwie do http) oraz ma mniej sensu (aplicacje konsolowe są zwykle małe i łatwiej je testować po kawałku niż aplikacje webowe).
Kiedyś próbowałem testować tak swoją aplikację konsolową i mało z tego zysku było. Ostatecznie większość testów przepisałem na normalne testy gdzie wywoływałem metodę main, albo moją funkcję run zawierającą interesujący mnie kod biznesowy

nie znamy wnętrza "czarnej skrzynki"

Jakbyś znał wnętrze czarnej skrzynki to nie była by już czarną skrzynką tylko białą skrzynką. Na tym polegają testy czarnoskrzynkowe że nie znasz wnętrza a interesuje cię tylko API :)


Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie
AK
> próbowałem testować tak swoją aplikację konsolową i mało z tego zysku było. Dokladnie to mam na mysli
NO
  • Rejestracja:ponad 3 lata
  • Ostatnio:ponad 3 lata
  • Postów:6
0

@Shalom: @AnyKtokolwiek: Moje wcześniejsze metody testowe opierają się na wyniku wywołania metody main() jednak to nie zadziała w momencie testowania pustej listy argumentów ponieważ wtedy rzucony zostaje NullPointerException, a to nie to samo co zostaje rzucone gdy odpalę aplikację z konsoli bez podania argumentów. Jeśli w konsoli nie podam argumentów to rzucony jest ArrayIndexOutOfBoundException, stąd pomysł na zrobienie tego przy pomocy ProcessBuildera ale jak rozumiem z powyższych wypowiedzi nie ma to większego sensu.

AK
To niekompatybilnie ze specyfikacją przygotowujesz parametry. Pusty string linii komendy != null dla maina, i tyle. testy dotyczą nie twojego kodu, a kodu rozbiegowego
NO
  • Rejestracja:ponad 3 lata
  • Ostatnio:ponad 3 lata
  • Postów:6
0

@AnyKtokolwiek: niestety nie znam pojęcia "kod rozbiegowy".
Wiem, że pusty String linii komendy != null ale to nadal nie rozwiązuje problemu ponieważ, jeśli przygotuję parametry tak aby stanowiły je puste Stringi to kod działa bez zarzutu. Po prostu najzwyczajniej kod oblicza, że pierwszy parametr występuje po "pierwszym znaku" w tekście, który jest drugim parametrem (pustym Stringiem). No i to się zgadza z punktu widzenia kodu, niestety nijak nie testuje to kodu ponieważ, raz jeszcze, aplikacja rzuca ArrayIndexOutOfBoundException gdy jest odpalona z pustą listą.
Nie mogę też zadeklarować, że lista jest nullem, to skutkuje NullPointerem.
A w takim wypadku nie mam pojęcia jak inaczej miałbym zadeklarować parametry tak, aby test wykazał rzeczywisty rezultat wywołania kodu.

YA
  • Rejestracja:prawie 10 lat
  • Ostatnio:3 minuty
  • Postów:2367
1

@novice: Trochę poza tematem przewodnim... Chcę przetestować, że aplikacja rzuci ArrayIndexOutOfBoundsException w momencie gdy pierwszy, drugi lub obydwa parametry są puste. - serio masz taką aplikację, która rzuca tym wyjątkiem jak nie podasz właściwych parametrów? Z perspektywy szarego użytkownika jest to nieczytelna informacja. Przeważnie aplikacje produkują coś w stylu: usage: --help, -h for help, jeśli parametry są wymagane i użytkownik nie poda wymaganych.

Jeśli masz możliwość, to wysiłek włóż w poprawienie aplikacji, a nie w obejścia na potrzeby testów. Może warto rozdzielić "parsowanie" parametrów uruchomieniowych od biznesowego użycia tychże?

NO
  • Rejestracja:ponad 3 lata
  • Ostatnio:ponad 3 lata
  • Postów:6
0

@yarel: Nie ja jestem twórcą tej aplikacji, a sam testuję ją w ramach ćwiczeń. Gdyby to była moja apka to inaczej rozwiązałbym kwestię tego wyjątku. Poza tym tak na prawdę nie chodzi mi o przetestowanie tego konkretnego wyjątku, a jedynie poprawne przetestowanie, że aplikacja się wysypuje jeśli jeden lub obydwa argumenty są puste. Stąd wydaje mi się, że przetestowanie tego wyjątku byłoby najbardziej sensowne, bo nie widzę innej możliwości.

AK
  • Rejestracja:ponad 6 lat
  • Ostatnio:4 dni
  • Postów:3561
0

Właśnie @yarel w pełni sie zgadzam, coś mi nie gra pod względem zaangażowania energii.

Nie rozumiem @novice dlaczego

Kopiuj

String[] args = ...

AnEntryClass.main(args)

nie miałoby zaskutkować


Bo C to najlepszy język, każdy uczeń ci to powie
edytowany 1x, ostatnio: AnyKtokolwiek
NO
  • Rejestracja:ponad 3 lata
  • Ostatnio:ponad 3 lata
  • Postów:6
0

@yarel: @Shalom: @AnyKtokolwiek: Dobra, nie jestem zbyt bystry... Z uporem maniaka chciałem "coś" wepchnąć do tej listy parametrów. Albo puste Stringi albo nulle, stąd te niechciane wyniki. A wystarczyło zadeklarować tablicę parametrów bez tworzenia instancji lub stworzyć instancję tablicy o długości 0...
Dziękuję w każdym razie za wszystkie wskazówki, aż mi głupio z powodu tej ignorancji :/

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)