203 lines
8.0 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package fr.enssat.BoulderDash.models;
import fr.enssat.BoulderDash.helpers.AudioLoadHelper;
import fr.enssat.BoulderDash.helpers.LevelLoadHelper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
public class LevelModelTest {
private LevelModel levelModel;
DisplayableElementModel[][] groundLevelModel;
LevelLoadHelper levelLoadHelper;
AudioLoadHelper audioLoadHelper;
GameInformationModel gameInformationModel;
@BeforeEach
public void setUp() {
levelLoadHelper = mock(LevelLoadHelper.class);
audioLoadHelper = mock(AudioLoadHelper.class);
gameInformationModel = mock(GameInformationModel.class);
// boundaries and 2x2 field inside
when(levelLoadHelper.getHeightSizeValue()).thenReturn(4);
when(levelLoadHelper.getWidthSizeValue()).thenReturn(4);
when(levelLoadHelper.getRockfordPositionX()).thenReturn(1);
when(levelLoadHelper.getRockfordPositionY()).thenReturn(1);
when(levelLoadHelper.getRockfordInstance()).thenReturn(new RockfordModel());
when(levelLoadHelper.getGroundGrid()).thenReturn(
new DisplayableElementModel[4][4]
);
// We add one diamond below, thus return 1.
when(levelLoadHelper.getDiamondsToCatch()).thenReturn(1);
levelModel = new LevelModel(levelLoadHelper, audioLoadHelper, "game");
// Place diamond next to Rockford
levelModel.getGroundLevelModel()[1][2] = new DiamondModel();
groundLevelModel = levelModel.getGroundLevelModel();
}
/**
* During an ongoing game, the player character is moved to an exit. The following
* behavior is expected and should be verified:
* • The game ends.
* • The player character is located on the field where the exit was previously located.
* • No sound is played.
*/
@Test
void test1bi(){
// Place exit next to Rockford
levelModel.getGroundLevelModel()[2][2] = new DoorModel();
// Move Rockford from (1,1) to (2,2)
levelModel.setPositionOfRockford(2,2);
// Verify:
// Game ended
assertFalse(levelModel.isGameRunning());
// Rockford is located at exit/door
assertEquals(2, levelModel.getRockfordPositionX());
assertEquals(2,levelModel.getRockfordPositionY());
// The sounds are played in a different thread after an action occurred.
// This might happen after we verify the number of method calls.
// To avoid this, we sleep one second.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// No sound is played
verify(audioLoadHelper, never()).playSound(anyString());
}
/**
* During an ongoing game, the player character collects the last diamond. The
* following behavior is expected and should be verified:
* • The score increases by 1.
* • The number of remaining diamonds decreases to 0.
* • Exactly one exit appears on the game field.
* • The player character is located on the field where the diamond was previously located.
* • The starting field of the player character becomes an empty field.
* • The sound for collecting a diamond is played.
*/
@Test
void test1bii(){
int oldScore = levelModel.getGameInformationModel().getScore();
int oldRemainingDiamonds = levelModel.getGameInformationModel().getRemainingsDiamonds();
// Verify:
// 1 Remaining diamond
assertEquals(1, oldRemainingDiamonds);
// No exit.
assertEquals(0, numOfExits());
// Move Rockford from (1,1) to (1,2)
levelModel.setPositionOfRockford(1,2);
// Verify:
// Score increased by 1
assertEquals(oldScore + 1, levelModel.getGameInformationModel().getScore());
// No remaining diamonds
assertEquals(0, levelModel.getGameInformationModel().getRemainingsDiamonds());
// Verify: One exit appeared.
// Math.random -> sometimes spawned at old or new position of Rockford,
// then this assertion fails
assertEquals(1, numOfExits());
// Rockford placed at previous diamond location
assertEquals(1, levelModel.getRockfordPositionX());
assertEquals(2,levelModel.getRockfordPositionY());
// The starting field of Rockford becomes an empty field
assertInstanceOf(EmptyModel.class, groundLevelModel[1][1]);
// The sounds are played in a different thread after an action occurred.
// This might happen after we verify the number of method calls (which would make this test fail).
// To avoid this, we sleep one second.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// The sound for collecting a diamond is played.
verify(audioLoadHelper).playSound("coin");
}
int numOfExits(){
// We can't use
// verify(levelModel, times(1)).spawnExit();
// as spawnExit() is a private method.
// Iterate over the ground level and count DoorModel objects.
return (int) Arrays.stream(groundLevelModel)
.flatMap(Arrays::stream)
.filter(x -> x instanceof DoorModel)
.count();
}
/**
* During an ongoing game, the player character collects the last diamond again.
* However, this test case should minimize concrete state changes in the application and instead verify that the appropriate methods are called with the
* correct parameters to achieve the desired behavior. Explain and justify for
* which of the following points this is not possible. The following behavior is
* expected and should be verified:
* • The increase in score is triggered.
* • The decrease in the number of remaining diamonds is triggered.
* • The appearance of an exit on the game field is triggered.
* • The update of the player characters position is triggered.
* • Replacing the player characters starting field with an empty field is triggered.
* • Playing the sound for the entered field is triggered.
*/
@Test
void test1biii(){
GameInformationModel gameInformationModel = mock(GameInformationModel.class);
levelModel.setGameInformationModel(gameInformationModel);
levelModel = spy(levelModel);
// Move Rockford from (1,1) to (1,2)
levelModel.setPositionOfRockford(1,2);
// Verify:
// increase score
verify(gameInformationModel).incrementScore();
// decrease remaining diamonds
verify(gameInformationModel).decrementRemainingsDiamonds();
// exit appearance - IMPOSSIBLE
// 'spawnExit()' has private access
// We can only verify there are no remaining diamonds
verify(gameInformationModel).getRemainingsDiamonds();
// update character's position
verify(levelModel).updateRockfordPosition(anyInt(), anyInt());
// replace with empty field - IMPOSSIBLE
// We can't verify if the field at the position is being emptied,
// because this happens inside the method setPositionOfRockford using a constructor call:
// `this.groundGrid[oldX][oldY] = new EmptyModel();`
assertInstanceOf(EmptyModel.class, groundLevelModel[1][1]);
// The sounds are played in a different thread after an action occurred.
// This might happen after we verify the number of method calls (which would make this test fail).
// To avoid this, we sleep one second.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// The sound for collecting a diamond is played.
verify(audioLoadHelper).playSound("coin");
}
}