Parametryczne testy Junit timeout

0

Witam,
Mam problem z testem parametrycznym Junit. Kiedy uruchamiam każdy test z kategorii upTo5sec osobno wtedy testy uruchamiają się bez błędów. Kiedy uruchomię wszystkie testy na raz wtedy niektóre dają timeout a w niektórych pojawiają się błędy. To jest tak jakby test brał wynik z timeout i porównywał z innym testem i wtedy expected nie równa się result.. Nie wiem w czym problem.

Testy są zdefiniowane w pliku list.txt(src/test/fz/upTo5sec/). Można ją wygenerować skryptem bash listgenerator (src/test/fz/upTo5sec/listgenerator)

Poprawiony link poprzedni nie pokazywał błędów w testach: LINK
Uruchomić chyba najlepiej z Intellij Idea

0

JVM robi sporo optymalizacji, podczas wykonywania kodu, niektóre dopiero po kilku uruchomieniach; Spróbuj dać mu jakiś warmup:) Zablokuj GC, może coś się stanie. To przy założeniu, że nie Masz błędów, jak gdzieś jest niewłaściwy wynik, to dupa debugging:) niestety.

0

Ściągnąłem, skompilowałem, uruchomiłem i wniosek jest taki:

 @Test
    public void testMinizinc() throws IOException, InterruptedException {
        String expected = "";//"src/test/fz/scriptGolden/" + expectedDir;
        String res = "";
        String expectedFzn = "";
        String resFzn = "";

        expectedDir = Paths.get(itrScriptGold.next());
        Path resultDir = Paths.get(itrScriptTest.next());


        File file = new File("src/test/fz/scriptGolden");
        String[] directories = file.list(new FilenameFilter() {
            @Override
            public boolean accept(File current, String name) {
                return new File(current, name).isDirectory();
            }
        });




        for(int i=0; i<directories.length; i++) {
            if(new File("src/test/fz/scriptGolden/" + directories[i] + "/" + resultDir + ".fzn").exists() ){

                expectedDir =  Paths.get( directories[i]+"/" + resultDir );
            }
        }

        if (new File("src/test/fz/upTo5sec/" + Paths.get(this.testFilename).getParent()).isDirectory()) {
            res = "src/test/fz/upTo5sec/" + resultDir + ".out";
            expected = "src/test/fz/scriptGolden/" + expectedDir + ".out";
            resFzn = "src/test/fz/upTo5sec/" + resultDir + ".fzn";
            expectedFzn = "src/test/fz/scriptGolden/" + expectedDir + ".fzn";
        } else if (new File("src/test/fz/upTo30sec/" + Paths.get(this.testFilename).getParent()).isDirectory()) {
            res = "src/test/fz/upTo30sec/" + resultDir + ".out";
            expected = "src/test/fz/scriptGolden/" + expectedDir + ".out";
            resFzn = "src/test/fz/upTo30sec/" + resultDir + ".fzn";
            expectedFzn = "src/test/fz/scriptGolden/" + expectedDir + ".fzn";
        } else if (new File("src/test/fz/upTo1min/" + Paths.get(this.testFilename).getParent()).isDirectory()) {
            res = "src/test/fz/upTo1min/" + resultDir + ".out";
            expected = "src/test/fz/scriptGolden/" + expectedDir + ".out";
            resFzn = "src/test/fz/upTo1min/" + resultDir + ".fzn";
            expectedFzn = "src/test/fz/scriptGolden/" + expectedDir + ".fzn";
        } else if (new File("src/test/fz/upTo5min/" + Paths.get(this.testFilename).getParent()).isDirectory()) {
            res = "src/test/fz/upTo5min/" + resultDir + ".out";
            expected = "src/test/fz/scriptGolden/" + expectedDir + ".out";
            resFzn = "src/test/fz/upTo5min/" + resultDir + ".fzn";
            expectedFzn = "src/test/fz/scriptGolden/" + expectedDir + ".fzn";
        } else if (new File("src/test/fz/upTo1hour/" + Paths.get(this.testFilename).getParent()).isDirectory()) {
            res = "src/test/fz/upTo1hour/" + resultDir + ".out";
            expected = "src/test/fz/scriptGolden/" + expectedDir + ".out";
            resFzn = "src/test/fz/upTo1hour/" + resultDir + ".fzn";
            expectedFzn = "src/test/fz/scriptGolden/" + expectedDir + ".fzn";
        } else if (new File("src/test/fz/above1hour/" + Paths.get(this.testFilename).getParent()).isDirectory()) {
            res = "src/test/fz/above1hour/" + resultDir + ".out";
            expected = "src/test/fz/scriptGolden/" + expectedDir + ".out";
            resFzn = "src/test/fz/above1hour/" + resultDir + ".fzn";
            expectedFzn = "src/test/fz/scriptGolden/" + expectedDir + ".fzn";
        } else if (new File("src/test/fz/flakyTest/" + Paths.get(this.testFilename).getParent()).isDirectory()) {
            res = "src/test/fz/flakyTest/" + resultDir + ".out";
            expected = "src/test/fz/scriptGolden/" + expectedDir + ".out";
            resFzn = "src/test/fz/flakyTest/" + resultDir + ".fzn";
            expectedFzn = "src/test/fz/scriptGolden/" + expectedDir + ".fzn";
        } else if (new File("src/test/fz/errors/" + Paths.get(this.testFilename).getParent()).isDirectory()) {
            res = "src/test/fz/errors/" + resultDir + ".out";
            expected = "src/test/fz/scriptGolden/" + expectedDir + ".out";
            resFzn = "src/test/fz/errors/" + resultDir + ".fzn";
            expectedFzn = "src/test/fz/scriptGolden/" + expectedDir + ".fzn";
        }

//            System.out.println(expected);
        ProcessBuilder pb1 = new ProcessBuilder("diff", "-r", res, expected);
        Process p2 = pb1.start();
        p2.waitFor();

        ProcessBuilder pb3 = new ProcessBuilder("diff", "-r", resFzn, expectedFzn);
        Process p4 = pb3.start();
        p4.waitFor();

        boolean result = false;

        if (0 == p2.waitFor() && 0 == p4.waitFor() ) {
            result = true;
            System.out.println(expected +"\n" + expectedFzn);
        }


        String s = null;
        String ss = null;
        BufferedReader stdInput = new BufferedReader(new InputStreamReader(p2.getInputStream()));
        BufferedReader stdInputFzn = new BufferedReader(new InputStreamReader(p4.getInputStream()));
        while ((s = stdInput.readLine()) != null || (ss = stdInputFzn.readLine()) != null) {
            if( s != null) {
                System.out.println(expected + "\n" + s);
            }
            if( ss != null) {
                System.out.println(expectedFzn + "\n" + ss);
            }
        }

        Assert.assertEquals(true, result);


    }

diff zwraca wartość inną niż 0, gdy porównywane pliki są różne. Pytanie co powoduje różnice. Poza tym weź może, to rozbij na wiele przypadków testowych, bo ta drabinka ifów jest chora.

0

Patrzysz nie na to co masz to taki test skryptu. To jest nie istotne w tym temacie.

Chodzi o to: src/test/java/org/jacop/MinizincBasedTestUpTo5Seconds.java i tutaj jak uruchomisz jakimś cudem timeout wpływa na inny test parametryczny który daje błędny wynik.

Minimalna konfiguracja jaka daje błędy poniżej. Wystarczy wkleić w list.txt(src/test/fz/upTo5sec/list.txt) zamiast tego co tam jest i uruchomić MinizincBasedTestUpTo5Seconds.java.

assignment2/assignment2
atmost1_me/atmost1_me
bacp/bacp-22
bacp/bacp-21

Co ciekawe jak przestawię assignment2 z atmos1 w list.txt to błędu nie ma i testy przechodzą. Czyli jak zmienię kolejność w pliku list.txt na taką:

atmost1_me/atmost1_me
assignment2/assignment2
bacp/bacp-22
bacp/bacp-21

0

A mi wysypało się wcześniej. Swoją drogą jeżeli masz problem, który można rozwiązać za pomocą zmiany kolejności testów, to oznacza, że testy te współdzielą jakieś dane. Pytanie, co to za dane?

0

Ktoś mi zasugerował, że testy nie powinny wykonywać operacji na plikach i w tym może być problem.

0

Jeżeli mają to być testy jednostkowe, to oczywiście nie powinny dotykać plików. Testy jednostkowe z definicji są izolowane od otoczenia. Pytanie co chcesz przetestować. Jeżeli do testu wymagana jest większa ilość danych, bo taki jest algorytm, to użycie plików jako źródła danych będzie OK. W przypadku powyższego testu problem jest zupełnie inny :) Zamykasz w dużym ifie jakiś rodzaj "magii", która decyduje o zasadach uruchomienia testu. To tylko zaciemnia obraz i nie widać czy nie powstają niejawne zależności pomiędzy testami.

0

W dużym ifie ? Ten test używa dwóch plików MinizincBasedTestsHelper.java i MinizincBasedTestUpTo5Seconds.java. O jaki if chodzi ?

To jedyny fragment kodu używający ify:

if (result.size() == 0)
            fail("\n" + "File path: " + timeCategory + testFilename + ".fzn " + " gave no output to compare against.");

        for (int i = 0, j = 0; i < result.size() || j < expectedResult.size(); ) {
            if (i < result.size() && result.get(i).trim().isEmpty()) {
                i++;
                continue;
            }
            if (j < expectedResult.size() && expectedResult.get(j).trim().isEmpty()) {
                j++;
                continue;
            }
            if (result.size() == i)
                fail("\n" + "File path: " + timeCategory + testFilename + ".out "
                    + " gave as a result less textlines that was expected. Expected line " + (j + 1) + " not found.");
            if (expectedResult.size() == j)
                fail("\n" + "File path: " + timeCategory + testFilename + ".out "
                    + " gave as a result more textlines that was expected. Actual line " + (i + 1) + "not found in expected result");

            assertEquals(
                "\n" + "File path: " + timeCategory + testFilename + ".out " + "\nError line number (expected, actual): (" + (j + 1) + ","
                    + (i + 1) + ")\n", expectedResult.get(j).trim(), result.get(i).trim());
            i++;
            j++;

        }
2

I teraz powiedz mi, laikowi, który nie zna domeny, co ten test sprawdza? Nazewnictwo, użycie ifów zamiast assert/assume, w efekcie nie wiesz co sie dzieje.

edit:

Swoją drogą przepisałem to w ten sposób:

public class MinizincBasedTestsHelper {
    protected String testFilename;
    protected static Fz2jacop fz2jacop;
    protected static final String relativePath = "src/test/fz/";
    protected static String timeCategory;
    protected static final String listFileName = "list.txt";
    protected static final boolean printInfo = true;

    @BeforeClass public static void initialize() {
        fz2jacop = new Fz2jacop();
    }



    protected static List<String> result(String filename) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PrintStream old = System.out;
        System.setOut(new PrintStream(baos));

        try {
            fz2jacop.main(new String[] {relativePath + filename});
        } finally {

            System.out.flush();
            System.setOut(old);

            String result = baos.toString();
            if (printInfo) {
                System.out.println(filename + "\n" + result);
            }
            return Arrays.asList(result.split("\n")).stream().filter(l->!l.isEmpty()).map(String::trim).collect(Collectors.toList());
        }

    }

    protected static List<String> expected(String filename) throws IOException {
        String filePath = new File(relativePath + filename).getAbsolutePath();
        return Files.readAllLines(Paths.get(filePath), StandardCharsets.UTF_8).stream().filter(l->!l.isEmpty()).map(String::trim).collect(Collectors.toList());
    }

    protected static Collection<String> fileReader(String timeCategory) throws IOException {
        System.out.println("timeCategory" + timeCategory);
        FileReader file = new FileReader(relativePath + timeCategory + listFileName);
        BufferedReader br = new BufferedReader(file);
        String line = "";
        List<String> list = new ArrayList<String>();
        int i = 0;
        while ((line = br.readLine()) != null) {
            list.add(i, line);
            i++;
        }
        return list;
    }

    protected void testExecution(String timeCategory) throws IOException {

        System.out.println("Test file: " + timeCategory + testFilename);

        List<String> expectedResult = expected(timeCategory + testFilename + ".out");
        List<String> result = result(timeCategory + testFilename + ".fzn");

        assertNotEquals("" + "File path: " + timeCategory + testFilename + ".fzn " + " gave no output to compare against.", 0, result.size());
        assertEquals(result, expectedResult);
    }
}

I nagle okazuje się, że można, to przeczytać. Jedyne co pozostaje t timeouty, i jakieś różnice w samych plikach. Jednak jest tu więcej błędów w samym kodzie np. protected static, które wprowadzają zamieszanie.

Timeouty – prosta przyczyna, niektóre testy wykonują się bardzo długo. Jest to powtarzalne zachowanie dla konkretnych testów i moim zdaniem wynika, to z ilości danych, które muszą przerobić. Czasami wystarczy, by maszyna musiała się zająć czymś innym np. odpalony został GC, i już mamy po teście.
Zależności – być może występuje to tylko u mnie, ale zazwyczaj wysypuje się test, który jest uruchomiony po teście, który miał timeout. Wniosek, testy nie sprzątają po sobie. Dodatkowo walą raźnie na System.out, który jest synchronizowany i mieszają się informacje.

0

No tak z tymi lambdami z pewnością jest lepiej. Same timeouty nie są problemem tylko te błędy po nich. Ale to pewnie wina czyszczenia.


protected static List<String> result(String filename) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PrintStream old = System.out;
        System.setOut(new PrintStream(baos));

        try {
            fz2jacop.main(new String[] {relativePath + filename});
        } finally {

            System.out.flush();
            System.setOut(old);

            String result = baos.toString();
           
            System.out.println(filename + "\n" + result);
           

            return Arrays.asList(result.split("\n"));

        }

    }

Jakby ktoś miał jakiś pomysł w czym jest problem to będę wdzięczny :)

0

Używam finally clause żeby posprzątać zmiany na System.out ale może to powoduje jakieś problemy ? Jak jeszcze mógłbym to posprzątać ?

0

Po co nadpisujesz System.out. Nie lepiej jest wykorzystać Logger?

0

Hmm mogę spróbować. Tylko to to nie wyjaśnia dlaczego to nie działa tak jak powinno.

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