Maybe what I am trying to do is not worthwhile, it sure feels that way after spending many days on it.
I have A Base Class shown here:
package jimmy.kilmer.com;
import java.awt.Color;
import jarPackageImports.AI;
import jarPackageImports.MovementAction;
import jarPackageImports.Info;
import jarPackageImports.PlayerAction;
public class GameAI extends AI {
public gameAI(Info info) {
super(info);
setJerseyNumber(32);
}
public Color getColor() {
return Color.RED;
}
public String getName() {
return "Usain Bolt";
}
public PlayerAction update() {
// TODO game movement actions
// all available methods not listed here...
info.getVelocity();
info.getX();
info.getY();
MovementAction steeringBehavior = null;
return steeringBehavior;
}
//basically used for testing setup
public int[][] populateAllPossibleNodes() {
int[][] allPossibleNodes = new int[screenWidth/20][screenHeight/20];
return allPossibleNodes;
}
}
I have been given a jar, that sets up the game environment. It uses reflection for the setup. I am not familiar with reflection, unfortunately, as I am more beginner level.
I have read a lot about TDD, and am convinced that can help me stay orderly, and code in a disciplined way. I have some say that TDD is not really useful for Game development, which the arguments may be true, in regard to making an "enjoyable game." But, from a purely coding standpoint, I remain steadfast in my believe that TDD is the way to go. But, that remains to be seen, since it is still theoretical. I would like to try it.
I have installed Junit 5, and have done many tutorials, but it's all pretty basic examples. My particular test case uses reflection, super classes, derived classes, dynamic data. My head is spinning.
My goal is just to get setup such that I can start doing some Test driven development.
Here is my Junit test class:
package jimmy.kilmer.com;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import jarPackageImports.Info;
class GameAITest {
private GameAITest AIObject;
private jarPackageImports.Info info;
#BeforeEach
void setUp() throws Exception {
AIObject = new GameAITest(info);
#AfterEach
void tearDown() throws Exception {
}
#Test
void testPopulateAllPossibleNodes() {
// 1. given/arrange
int[][] array1 = new int[80][65];
// 2. when/act
int[][] array2 = AIObject.populateAllPossibleNodes();
// 3. then/assert
assertArrayEquals(array1, array2);
}
}
That is my best stab so far, but it still get a compile error. Specifically:
java.lang.NullPointerException:Cannot invoke "jarPackageImports.Info.getScene()" because "this.info" is null
In summation:
maybe everything I am trying is rubbish?
Do I need to use dynamic junit testing? I would have to read up on that.
Do I need to mock (use Mockito?) to instantiate an object to test? I would need to read up on that as well.
Is it possible to instantiate an object from GameAI? Do I need to/how would I use relection to do that? class.getConstructors()? And, I would have to read up on that.
thanks in advance.
Related
I am trying to understand Unit testing and how the correct classes are being fetched on test time,
I'm having a hard time understanding exactly what is going on behind the scenes and how safe/correct my usages for this are.
This is a very simple example of what i am trying to do, i wrote it here inline so it probably contains some errors, please try to ignore them, as stupid as they may be.
A very simple project directory:
ba/src/main/java/utils/BaUtils.java
ba/test/main/java/utils/BaUtilsTest.java
notBa/src/main/java/im/BaObj.java
BaUtils.java code:
package com.ba.utils;
import notBa.im.BaObj;
public class BaUtils{
public String doSomething(BaObj obj){
obj.doSomething();
}
}
I would like to test BaUtils wihtout actually calling doSomething, and i can't change anything on BaObj class or notBa package. I know that i can (by 'can' i mean it will work) add a new java file to 'ba' project (ba/test/java/notBa/main/java/im/BaObj.java) that will have the same package as the original BaObj, and at runtime the test will import this one instead of the real one, so BaUtils code is tested but BaObj code is not excecuted.
that should look something like like :
package notBa.im.Baobj
public class BaObj{
public void doSomething(){
System.out.println("Did something");
}
}
My questions are (And thank you for reaching this far):
How does this work (Reading references would be great).
Is this kind of test building considered 'good' or 'safe' ?
Thanks!
The solution is to use a mocking framework (I for myself like Mockito).
The test would look like this:
class BlaUtilTes{
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#Mock
Blaobj blaobj;
#Test
public void doSomething_WithMockedBlaobj_callsDosomethingOnBlaobj(){
// arrange
BlaUtil blaUtil= new BlaUtil();
// act
blaUtil.doSomething(blaobj);
// assert
Mockito.verify(blaobj).doSomething();
}
}
find more information here http://www.vogella.com/tutorials/Mockito/article.html#testing-with-mock-objects
Your BaUtilsTest class should look like this.. I have used mockito for for mocking external dependencies. Also I changed the method return type to String for easy understanding.
#RunWith(MockitoJUnitRunner.class)
class BaUtilsTest {
BaUtils util;
#Mock
BaObj mockBaObj;
#Before
public void setup() {
util = new BaUtils();
}
#Test
public void testDoSomething() {
Mockito.when(mockBaObj.doSomething()).thenReturn("did the work using mock");
String result = util.doSomething(mockBaObj);
Assert.assertEquals("did the work using mock", result);
}
}
In a Saving account for the withdraw variables i need to make sure it can't withdraw more than 3 in a month. I checked the criteria in the setter but I'm not sure how to do the testing in the JUintTesting. As both of them are void method and the testing method returns a boolean i am getting a error of void below is my code.
public void setNumberWithdrawals(int w)
{
if (getNumberWithdrawals() > 3)
{
System.out.println("You already have more than 3 withdraw!!");
}
else
{
numberWithdrawals = w;
}
}
For JUNit testing
SavingsAccount sa1;
#Test
public void testsetNumberWithdrawals()
{
assertEquals(true, sa1.setTest(4));
}
I am expecting it to return false since i pass 4 but i keep on getting the void and return type expected error, i even tried assigning the value to another int variable for number and tested it but i still got the error.
Assumption: You're using JUnit 4 (seems like a safe assumption given that the code you provided is using the #Test annotation).
You would want something like this for your test class:
import static org.junit.Assert.*;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class SavingsAccountTest {
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
#Before
public void setUpStreams() {
System.setOut(new PrintStream(outContent));
System.setErr(new PrintStream(errContent));
}
#After
public void cleanUpStreams() {
System.setOut(null);
System.setErr(null);
}
#Test
public void test() {
SavingsAccount savingsAcct = new SavingsAccount(...);
savingsAcct.setNumberWithdrawals(...);
assertEquals("You already have more than 3 withdraw!!\r\n", outContent.toString());
}
}
Other thoughts:
Given the code you posted in your question and code on github some things seem a little strange. It might just be that some of the code is still missing, but I want to point out a few things that stand out:
You posted this code:
assertEquals(true, sa1.setTest(4));
Now according to what I read on github, sa1 is an instance of SavingsAccount yet I don't see a definition for this setTest(...) method anywhere. I do see this SavingsAccount extends Account so I suppose setTest(...) could be defined in the Account class. The reason this stands out is that you said you were trying to test SavingsAccount.setNumberWithdrawals(...) but you're not invoking setNumberWithdrawals in your test. Again, I suppose that this setTest method could indirectly invoke setNumberWithdrawals but that's not clear from everything you posted.
You said in your question:
make sure it can't withdraw more than 3
The logic you have is if (getNumberWithdrawals() > 3) which means the number of withdrawals will have to be more than 3 to trigger this logic. This seems to violate your requirement.
Using EasyMock 3.2. In order to unit test an UI, I have to mock some dependencies. One of them is Page. Base class for UI tests looks like this:
abstract class AbstractUiTest {
#Before
public function setUpUiDependencies() {
Page page = createNiceMock(Page.class);
Ui.setCurrentPage(page);
}
}
Most of the time I don't use the page explicity, it's just there not to throw NullPointerException when e.g. Ui calls getPage().setTitle("sth") etc.
However, in a few tests I want to explicity check if something has happend with the page, e.g.:
public class SomeTest extends AbstractUiTest {
#Test
public void testNotification() {
// do something with UI that should cause notification
assertNotificationHasBeenShown();
}
private void assertNotificationHasBeenShown() {
Page page = Ui.getCurrentPage(); // this is my nice mock
// HERE: verify somehow, that page.showNotification() has been called
}
}
How to implement the assertion method? I would really want to implement it without recording behavior to the page, replaying and verifying it. My problem is a bit more complicated, but you should get the point.
EDIT: I think that perhaps this is not really needed, since simply using replay and verify should check that the expected methods were actually called. But you said you want to do this without replaying and verifying. Can you explain why you have that requirement?
I think that you can use andAnswer and an IAnswer. You don't mention what the return value of page.showNotification() is. Assuming it returns a String, you could do this:
import static org.easymock.EasyMock.expect;
import static org.junit.Assert.assertTrue;
import java.util.concurrent.atomic.AtomicBoolean;
import org.easymock.IAnswer;
import org.junit.Ignore;
import org.junit.Test;
public class SomeTest extends AbstractUiTest {
#Test
public void shouldCallShowNotification() {
final AtomicBoolean showNotificationCalled = new AtomicBoolean();
expect(page.showNotification()).andAnswer(new IAnswer<String>() {
#Override
public String answer() {
showNotificationCalled.set(true);
return "";
}
});
replay(page);
Ui.getCurrentPage();
verify(page);
assertTrue("showNotification not called", showNotificationCalled.get());
}
}
If showNotification returns void, I believe you would need to do this:
import static org.easymock.EasyMock.expectLastCall;
import static org.junit.Assert.assertTrue;
import java.util.concurrent.atomic.AtomicBoolean;
import org.easymock.IAnswer;
import org.junit.Ignore;
import org.junit.Test;
public class SomeTest extends AbstractUiTest {
#Test
public void shouldCallShowNotification() {
final AtomicBoolean showNotificationCalled = new AtomicBoolean();
page.showNotification();
expectLastCall().andAnswer(new IAnswer<Void>() {
#Override
public Void answer() {
showNotificationCalled.set(true);
return null;
}
});
replay(page);
Ui.getCurrentPage();
verify(page);
assertTrue("showNotification not called", showNotificationCalled.get());
}
}
Note: I've used an AtomicBoolean to record whether the method was called. You could also use a boolean array of a single element, or your own mutable object. I used AtomicBoolean not for its concurrency properties, but simply because it is a handy mutable boolean object that is already present in the Java standard libraries.
The other thing that I have done to verify that a method was being called is to not use a mock at all, but to create an instance of Page as an anonymous inner class and override the showNotification method, and record somewhere that the call occurred.
Use a nice mock in the tests where you don't care what happens to page and a normal mock in those tests where you want to test something explicit - and use expect, verify etc. I.e. have two variables in your setup method: nicePage (acts as a stub) and mockPage (acts as a mock)
I'm trying some alterations in minecraft src. I'm trying to override a method in a class so I don't have to edit the original class.
In the regular class I want to alter this method:
public void sendChatMessage(String par1Str)
{
this.sendQueue.addToSendQueue(new Packet3Chat(par1Str));
}
So in my subclass I have this code:
package cobalt.gui;
import cobalt.hacks.*;
import net.minecraft.client.Minecraft;
import net.minecraft.src.EntityClientPlayerMP;
import net.minecraft.src.NetClientHandler;
import net.minecraft.src.Session;
import net.minecraft.src.World;
public class Console extends EntityClientPlayerMP {
public Console(Minecraft par1Minecraft, World par2World,
Session par3Session, NetClientHandler par4NetClientHandler) {
super(par1Minecraft, par2World, par3Session, par4NetClientHandler);
}
#Override
public void sendChatMessage(String par1Str) {
if (par1Str.startsWith(".help")) {
//Do stuff
return;
}
}
}
From my understanding, anytime a method is called, it should be "redirected" for the subclass to handle? (Tell me if I'm wrong ha)
The if statement does work correctly if I modify the original class.
Thank you very much!
This would only work if somehow the rest of the minecraft code starts using your class, Console, where it meant to use EntityClientPlayerMP. Without that, your function will not be called.
If you want to change the behavior of the game, the easiest way would be to change EntityClientPlayerMP itself. If you want to use the modified class Console elsewhere in the code, then what you have done is fine.
It depends on the actual object type. If the object is of type Console e.g. EntityClientPlayerMP obj = new Console(..) and obj.sendChatMessage(..) it'll work. But if the object itself is of type EntityClientPlayerMP like new EntityClientPlayerMP(..) It won't work
I'm interested in using the right mocking framework for my GWT app. It's my understanding that Mockito, EasyMock, and jMock are some of the most popular for Java. Could someone list pros/cons for the mocking framework that they are most familiar with as it relates to GWT to help fellow GWT testing noobs like myself?
Thanks in advance.
For the server side testing (RPC services) you can use any mocking framework you wish. spring-test library might be useful for mocking HttpRequest, HttpSession, and other classes of servlet api. Still you might have problems with testing classes extending RemoteServiceServlet, as they require properly encoded request. Here is interesting project which solves this problem:
http://www.gdevelop.com/w/blog/2010/01/10/testing-gwt-rpc-services/
When it comes to testing of client side GWT code (the part which is compiled into Java Script), you can extend GWTTestCase. However due to limited emulation of JRE library, lack of reflection API in particular, it would be impossible to use any mocking framework. What is more, GWTTestCase runtime is very slow, and for this reason consider as a base for integration testing rather than unit testing.
It is possible to create unit tests for GWT client code if GWT application follows Model View Presenter pattern. Assuming we are testing so called "Presenter" (logic) we can mock so called "Display" with any mocking framework. Here is example unit test using Mockito:
import static org.mockito.BDDMockito.*;
import org.junit.Test;
import com.google.gwt.user.client.ui.HasText;
public class ResultPresenterTest {
#Test
public void shouldSetItWorksResultText() {
// given
ResultPresenter.Display display = mock(ResultPresenter.Display.class);
MockButton button = new MockButton();
HasText label = mock(HasText.class);
given(display.getShowResultButton()).willReturn(button);
given(display.getResultLabel()).willReturn(label);
ResultPresenter presenter = new ResultPresenter();
presenter.bind(display);
// when
button.click();
// then
verify(label).setText("It works");
}
}
Here is the presenter:
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.user.client.ui.HasText;
public class ResultPresenter {
private Display display;
public interface Display {
HasClickHandlers getShowResultButton();
HasText getResultLabel();
}
public void bind(final Display display) {
this.display = display;
display.getShowResultButton().addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
showResult();
}
});
}
public void showResult() {
display.getResultLabel().setText("It works");
}
}
And here is small helper class:
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
public class MockButton implements HasClickHandlers {
private HandlerManager handlerManager = new HandlerManager(this);
public void click() {
handlerManager.fireEvent(new ClickEvent() {
});
}
#Override
public HandlerRegistration addClickHandler(ClickHandler handler) {
return handlerManager.addHandler(ClickEvent.getType(), handler);
}
#Override
public void fireEvent(GwtEvent<?> event) {
handlerManager.fireEvent(event);
}
}
It would make sense to call presenter.showResult() in 'when' section instead of button.click(), however as you can see mocking of event circulation is also possible.
Google GIN might be very useful, as it allows to bind different instances depending on runtime/test context. On non-GWTTestCase presenter test GIN can be replaced with Guice.
The com.google.gwt.junit.GWTMockUtilities might be also very useful.
We're happily using Gwt-test-utils for our GWT project.
Mocking RPC calls with mockito is really easy :
First you declare your mocked service in your test :
#Mock
private ServiceAsync service;
then when you want to mock a successful callback :
doSuccessCallback(result).when(service).myMethod(eq("argument"), any(AsyncCallback.class));
More on that : http://code.google.com/p/gwt-test-utils/wiki/MockingRpcServices