Junit +input

0

Witam, swoją przygodę z programowanie zacząłem stosunkowo nie dawno, więc potrzebuje pomocy, a mianowicie z testowaniem. Stworzyłem projekt consolowego RPG'a - wraz z wiekszeniem ilosci metod, każdorazowe odpalanie całej aplikacji jest żmudne, zatem ogarnąłem kilka artykułów dt. JUnit.
W projekcie mam już kilka switchów, ale dotarłem do momentu, kiedy wklepywanie danych od nowa jest katorgą.
Nie bardzo wiem, jak ugryźć testowanie metody, która ma w sobie input.

public void chooseNextArea() throws InterruptedException {
System.out.println("Pierwsze wyzwanie za toba, wybierz teren do którego chcesz się udać: 1 - Bagna, 2 - Las");

    Scanner scanner2 = new Scanner(System.in);
    int choose;

    do {
        choose = scanner2.nextInt();
        switch (choose) {
            case 1:
                System.out.println("Wybierasz się na bagna...");
                Thread.sleep(4000);
                Swamps.beginingOfSwamps(); 
                break;
            case 2:
                System.out.println("Wybierasz się do lasu");
                Thread.sleep(4000);
                Forest.beginingOfForst();
                break;
            default:
                System.out.println("Wybierz między 1 lub 2");
                break;
        }
    } while (choose != 1 && choose != 2);
    System.out.println();
}
2

Wydaje mi sie, że najprościej na początek będzie wrzucenie tego choose jako atrybut do metody. Wtedy będzie ją obchodzić tylko wartość tego choose, a nie jego pochodzenie. W tym przypadku pętle też trzeba wynieść poziom wyżej

Czyli:

public void chooseNextArea(int choose) { ... }
0

Dzięki za odpowiedz!
Wpakowanie jako argumentu faktycznie pozwoliło mi przetestować tę metodę, tylko po teście muszę kod przywrócić do starej wersji - chciałbym osiągnąć efekt przy którym będzie możliwe uniknięcie tego.

0

Dlaczego musisz przywrócić do starej wersji??

0

Zacznijmy od tego że wszystkie te kwestie konsolowe to tak naprawdę sprawy widoku/GUI. JUnitem wykonujesz testy jednostkowe testując pojedyncze metody swojej logiki czyli wykonujesz testy metod np. Forest.beginingOfForst(); itd. Dlatego też właśnie nie robi się w logice żadnych scannerów czy sysoutów żeby nie musieć nic wprowadzać bo to właśnie skutkuje tym co piszesz czyli wszystko sam muisz wprowadzać a testy junitowe mają być automatyczne i szybkie. W projektach webowych też nie testujesz wszystkiego przez klikanie po stronie czy robienie jakichś automatycznych testów które będą same klikały. JUnitem testujesz domenę a ewentualnie dodatkowe testy służą do sprawdzenia funkcjonowania całości (czy tam testerzy sobie klikają). Tak czy inaczej junitowe testy to jedno a testowanie GUI czy całości to drugie.

Co możesz więc zrobić. Najpierw to odseparuj sobie logikę biznesową od części wyświetlania tego. Po stronie GUI/konsoli nie może być żadnej logiki, może być za to po prostu delegowanie operacji dalej do modułów które się tym zajmują. Dzięki temu całą logikę będziesz mógł bez problemów przetestować.

Innym problemem jest jeszcze kwestia tego zatrzymywania wątku na 4s jak chodzisz po bagnach. Po pierwsze moim zdaniem to powinno się znaleźć po stronie logiki a nie widoku. Później najlepiej zrobić to tak żebyś mógł przekazywać dane przed rozpoczęciem zadania. Jeśli masz tam coś więcej niż tylko ten czas to może to być jakiś obiekt QuestParams a w nim czas ile coś takiego zajmuje. Dzięki temu w aplikacji będziesz mógł przekazywać wartości jakie tam chcesz (np. 4s) a w testach będziesz ustawiał na 0 i nie będziesz musiał czekać.

0
baant napisał(a):

Dlaczego musisz przywrócić do starej wersji??

Tracę interakcje z graczem poprzez zrezygnowanie ze Scannera. Chyba, że źle rozumiem testowanie z Junit i mogę tylko na potrzeby testowania w /test/java zmodyfikować kod, nieruszając w /src.

Co możesz więc zrobić. Najpierw to odseparuj sobie logikę biznesową od części wyświetlania tego. Po stronie GUI/konsoli nie może być żadnej logiki, może być za to po prostu delegowanie operacji >dalej do modułów które się tym zajmują. Dzięki temu całą logikę będziesz mógł bez problemów przetestować.

Trochę za skomplikowanie wytłumaczone jak na mój poziom jeszcze chyba :p

1

Powinieneś napisać logikę i 'GUI' osobno, dzięki czemu będzie mógł testować. Co to znaczy? Gra nie powinna sama się wyświetlać tylko zwracać informacje o swoim stanie jako jakiś obiekt i potem gdzie indziej to wyświetlać.

Jako przykład prosta gra i osobno UI do niej


final class Game {


    private final Random r;
    private final int maxNumber;
    private final int result;

    static Game newGame(int max){
        return new Game(new Random(),max);
    }
    
    static Game newGameWithRandom(Random r, int max){
        return new Game(r,max);
    }

    private Game(Random r, int maxNumber){
        this.r = r;
        this.maxNumber = maxNumber;
        result = r.nextInt(maxNumber);
    }

    Result attempt(int i){
        return i==result ? Result.CORRECT : getStatus(i);
    }

    private Result getStatus(int i) {
        return i<result? Result.TOO_LOW : Result.TOO_MUCH;
    }

    enum Result{
        CORRECT,TOO_LOW, TOO_MUCH;
    }

}

final class GameUI {

    public static void main(String[] args) {
        new GameUI().start();
    }

    private void start() {
        Scanner s = new Scanner(System.in);
        System.out.println("Podaj maksymalną liczbę");
        int max = s.nextInt();

        Game game = Game.newGame(max);

        while (true) {
            System.out.println("Podaj liczbę:");
            int attempt = s.nextInt();
            Game.Result result = game.attempt(attempt);
            if (result == Game.Result.CORRECT) {
                break;
            } else {
                System.out.println(result);
            }
        }

        System.out.println("Brawo");
    }
}

Dzięki temu możesz teraz w testach podając Random co do którego znasz kolejne liczby (da się łatwo je sprawdzić) zobaczysz czy w 'kontrolnych' warunkach wszystko ładnei działa

1 użytkowników online, w tym zalogowanych: 0, gości: 1