Home > Blockchain >  Java test with mongodb database
Java test with mongodb database

Time:01-08

Description

I am testing a bulk insert in a mobgoDB database, in the @BeforeEach method I instantiate the database, in the@AfterEach I delete all documents created in the puzzles-today collection.

But the last one always fails, have random result, sometimes the test passes sometimes it displays this 367 or 366 or 364 or 364.

I added @RepeatedTest(4) To make sure it doesn't vary.

The code :

Class test

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.List;

import com.github.mathieusoysal.codingame_stats.CodinGame;
import com.github.mathieusoysal.codingame_stats.puzzle.Puzzle;

import org.bson.Document;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;

import io.github.mathieusoysal.util.MongoDBMockTest;

public class PuzzleDaoTest extends MongoDBMockTest {

    private PuzzlesDao puzzleDao;

    @BeforeEach
    public void setUp() throws Exception {
        super.setUp();
        puzzleDao = new PuzzlesDao(mongoClient, "CodinGame-stats");
    }

    @AfterEach
    public void tearDown() throws Exception {
        mongoClient.getDatabase("CodinGame-stats")
                .getCollection(PuzzlesDao.PUZZLES_HISTORY_COLLECTION)
                .deleteMany(new Document());
        super.tearDown();
    }

    @Test
    void testSaveAll_shouldReturnTrue_withTwoPuzzles() {
        List<Puzzle> puzzles = new CodinGame().getPuzzles().subList(0, 2);
        assertTrue(puzzleDao.saveAll(puzzles));
    }

    @Test
    void testSaveAll_shouldAugmentCollectionSize_withTwoPuzzles() {
        List<Puzzle> puzzles = new CodinGame().getPuzzles().subList(0, 2);
        puzzleDao.saveAll(puzzles);
        assertEquals(puzzles.size(), countDocuments());
    }

    @RepeatedTest(4)
    void testSaveAll_shouldAugmentCollectionSize_withAllPuzzles() {
        List<Puzzle> puzzles = new CodinGame().getPuzzles();
        puzzleDao.saveAll(puzzles);
        assertEquals(puzzles.size(), countDocuments());
    }

    private long countDocuments() {
        return mongoClient.getDatabase("CodinGame-stats")
                .getCollection(PuzzlesDao.PUZZLES_HISTORY_COLLECTION)
                .countDocuments();
    }

}

Clone the project

To easily replicate this, you can clone the repository in the dev branch enter image description here

But this result is random, sometimes the test passes sometimes it displays a error.

anyone have any idea to fix this?

CodePudding user response:

The problem you have is not a test problem, but an implementation problem. Look at:

class PuzzlesDao...
    public boolean saveAll(List<Puzzle> puzzles) {
        List<WriteModel<Document>> bulkWrites = new ArrayList<>();
        GsonBuilder builder = new GsonBuilder();
        Gson gson = builder.create();
        puzzles.parallelStream()
                .forEach(puzzle -> bulkWrites.add(new InsertOneModel<>(Document.parse(gson.toJson(puzzle)))));
        BulkWriteOptions bulkWriteOptions = new BulkWriteOptions().ordered(false);
        BulkWriteResult bulkWriteResult = collection.bulkWrite(bulkWrites, bulkWriteOptions);
        return bulkWriteResult.wasAcknowledged();
    }

You are using parallelStream() without a closing operation like collect(..) or count(). The forEach code is still being executed while the bulk operation is already running. Thus the resulting behaviour is unpredictable. One heuristic is to never use any side-effects in forEach(). If you have to then using a simple for loop is the better choice in my opinion.

I recommend the following change:

public boolean saveAll(List<Puzzle> puzzles) {
    GsonBuilder builder = new GsonBuilder();
    Gson gson = builder.create();
    List<WriteModel<Document>> bulkWrites =
            puzzles.parallelStream()
                    .map(puzzle -> new InsertOneModel<>(Document.parse(gson.toJson(puzzle))))
                    .collect(Collectors.toList());
    BulkWriteOptions bulkWriteOptions = new BulkWriteOptions().ordered(false);
    BulkWriteResult bulkWriteResult = collection.bulkWrite(bulkWrites, bulkWriteOptions);
    return bulkWriteResult.wasAcknowledged();
}

I personally hardly ever use parallelStream() unless I can show that it improves performance in a worthwhile way, which it usually does not. Using just stream() gets rid of the intricacies of parallelism.

  •  Tags:  
  • Related