Reputation: 33
I'm trying to do some JUnit tests with a class on LibGDX but I'm getting a NullPointerError when trying to initialise said class, which traces back to using the ShapeRenderer.
Here is the class I have initialised:
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.game.Point;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import java.util.ArrayList;
import static java.lang.Math.abs;
public class Player{
int health;
int range;
public Point position;
ShapeRenderer shape = new ShapeRenderer();
public Sprite drawable;
public Player(int health, int range, Point position,Texture img){
this.health = health;
this.range = range;
this.position = position;
this.drawable = new Sprite(img);
drawable.setPosition(position.x - drawable.getWidth()/2,position.y - drawable.getHeight()/2);
}
public boolean inRange(Player target){
if(abs(target.position.x - this.position.x) < this.range &&
abs(target.position.y - this.position.y) < this.range){
return true;
}
return false;
}
public void drawBox(ArrayList<Player> target, OrthographicCamera camera, Sprite sprite) {
shape.setProjectionMatrix(camera.combined);
shape.begin(ShapeType.Line);
boolean redBox = false;
for(Player player: target) {
if (this.inRange(player)) {
redBox = true;
}
}
if (redBox) {
shape.setColor(Color.RED);
}
else {
shape.setColor(Color.GREEN);
}
shape.rect(position.x - range, position.y - range, range * 2, range * 2);
shape.end();
}
}
Here is the relevant code from PlayerTest:
import com.entities.Player;
import com.game.Point;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Assertions;
class PlayerTest {
@Test
public void testInRangeBoundary() {
Player e = new Player(0,5, new Point(5,5));
Assertions.assertTrue(e.inRange(new Player(0,0,new Point(9,0))));
}
}
And this is the error I get:
java.lang.NullPointerException
at com.badlogic.gdx.graphics.glutils.ShaderProgram.loadShader(ShaderProgram.java:209)
at com.badlogic.gdx.graphics.glutils.ShaderProgram.compileShaders(ShaderProgram.java:188)
at com.badlogic.gdx.graphics.glutils.ShaderProgram.<init>(ShaderProgram.java:171)
at com.badlogic.gdx.graphics.glutils.ImmediateModeRenderer20.createDefaultShader(ImmediateModeRenderer20.java:233)
at com.badlogic.gdx.graphics.glutils.ImmediateModeRenderer20.<init>(ImmediateModeRenderer20.java:56)
at com.badlogic.gdx.graphics.glutils.ShapeRenderer.<init>(ShapeRenderer.java:116)
at com.badlogic.gdx.graphics.glutils.ShapeRenderer.<init>(ShapeRenderer.java:111)
at com.badlogic.gdx.graphics.glutils.ShapeRenderer.<init>(ShapeRenderer.java:107)
at com.entities.Player.<init>(Player.java:22)
at PlayerTest.testInRangeBoundary(PlayerTest.java:10) <19 internal calls>
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) <9 internal calls>
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) <21 internal calls>
(for reference line 22 is the 'ShapeRenderer shape = new ShapeRenderer();' line)
I know that a NullPointerException usually means that something hasn't been initialised but I'm not sure what to do with this.
Any help would be much appreciated!
Upvotes: 1
Views: 343
Reputation: 7081
Gdx.gl
is null during testing, like all other Gdx
fields. What is happening here is that you are creating a new ShapeRenderer object in the Entity constructor. ShapeRenderer then tries to access libGDX's rendering APIs but they aren't initialized, so you get an exception.
Since you're not really testing whether your entity is being drawn correctly, but whether the inRange
method is working correctly, you want to prevent calling any of libGDX's API during testing.
There are many options to solve this. You could rearrange your code:
Entity
class and an EntityRenderer
class. You only test the former.drawBox
method. If I remember correctly, ShapeRenderer are rather heavy objects so you might want to do that anyway if you have many entities.Another possibility would be to mock libGDX's APIs during testing.
Gdx.gl = mock(GL20.class)
.HeadlessApplication
which will correctly initialize the Gdx
class.Both these options are described here. However, prefer refactoring your code when possible, it's a good practice to keep game logic and rendering separated.
Upvotes: 1