JUnit: setUp and tearDown methods not working as expected - java

I was trying to develop some code using TDD, but stumbled on a weird behavior: setUp and tearDown doesn't seem to be "cleaning up" after each test is executed. I expected each test (marked with #Test annotation) to be executed at a random order, one after the other, without influencing each other. With that in mind, I don't understand what is happening as it seems like one specific test (testaSomarMao) is influencing another specific test (testaSplit). The testaSplit test is failling on the first assert: I expected value 6, but I'm getting 9. Anybody can explain me what is going on?
JogadorTest.java
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class JogadorTest{
private static Jogador p1;
public JogadorTest(){
}
#Before
public void setUp(){
p1 = new Jogador();
}
#After
public void tearDown(){
p1 = null;
}
#Test
public void testaGetNome(){
assertEquals(null, p1.getNome());
}
#Test
public void testaGetPontos(){
assertEquals(0, p1.getPontos());
}
#Test
public void testaSetNome(){
p1.setNome("Lucas");
assertEquals("Lucas", p1.getNome());
}
#Test
public void testaSomarMao(){
p1.comprarCarta(1);
assertEquals(3, p1.somarMao(1));
}
#Test
public void testaSplit(){
p1.comprarCarta(1);
p1.comprarCarta(1);
assertEquals(6, p1.somarMao(1));
p1.split();
assertEquals(p1.somarMao(1), p1.somarMao(2));
}
}
Jogador.java
public class Jogador {
private static String nome;
private int pontos;
private static int mao[] = new int[13];
private static int mao2[] = new int[13];
public void parar() {
}
public void setNome(String novoNome){
nome = novoNome;
}
public static int getPontos() {
return 0;
}
public static void split() {
//Usamos mao2 para garantir que soh ocorra um split.
if(mao[0] == mao[1] && mao2[0] == 0){
mao2[0] = mao[1];
mao[1] = 0;
}
}
public void fecharJogo() {
}
public String getNome() {
return nome;
}
public static int somarMao(int maoEscolhida){
int soma = 0;
int cartasNaMao[];
if(maoEscolhida == 2)
cartasNaMao = mao2;
else
cartasNaMao = mao;
for(int i = 0; i < cartasNaMao.length; i++)
soma += cartasNaMao[i];
return soma;
}
public static void comprarCarta(int maoEscolhida){
int carta = 3; // random futuramente
int cartasNaMao[];
if(maoEscolhida == 2)
cartasNaMao = mao2;
else
cartasNaMao = mao;
for(int i = 0; i < cartasNaMao.length; i++){
if(cartasNaMao[i] == 0) {
cartasNaMao[i] = carta;
break;
}
}
}
}

The underlying reason for your problem is, as pointed out by Thevenin, the use of static variables for mao[] and mao2[]
You will also need to remove static from methods comprarCarta and somarMao. You will not need it after all variables referenced inside are not static anymore. From the test it is obvious you are not using them in the way static methods are invoked usually, i.e Jogador.comprarCarta(1) instead of p1.comprarCarta(1).
My guess is you created those methods static and compiler then complained that your variables are not static and cannot be accessed, so you changed the variables as well.
Actually the use of static will cause you issues with other parts of your program as well - you better change nome variable to not be static. Same applies for getPontos() method - if you try to return pontos there instead of 0 you will get a compiler error that pontos is not static.
As you are confusing the use static in general take a look at this great explanation of what is static, when you have the time :)
Static variables - what are they?

In comprarCarta() you are modifying mao or mao2 which are static arrays. Any changes you make to these arrays will persist across all instances of Jogador.
Since this is not what you expect I suspect that you may not want these to be static.

Related

Is there any flaw in the below design ? My intention is whenever an object is created, unique id has to be generated

public class Test {
private static int counter = 1;
int uniqueId;
public Test() {
uniqueId = counter++;
}
public int getUniqueId() {
return uniqueId;
}
}
public class TestSub {
public static void main(String args[]) {
Test a = new Test();
Test b = new Test();
}
}
Assuming that:
the scope of int is large enough for your needs
you will not work with more than one thread at a time
you do not need randomness (for security reasons)
it should do exactly what you're describing.

Use an object in other methods of a test class

I have a test class in Android test package. There is a class that I've create an object in it. But other method of this test class can not use this object and can not recognize the result of that method. Why and what should I do? I used static too but can't...
#RunWith(AndroidJUnit4.class)
public class PatientDaoTest {
private static int newRowId;
public static PatientRecordEntity newPatient1;
public void generationRecord(){
newRowId = 0;
PatientRecordEntity newPatient1 = new PatientRecordEntity();
newPatient1.setPatient_db_ID("23456");
newPatient1.setPatient_race("Chines");
newRowId = (int) patientDao.addNewPatient(newPatient1);
newPatient1.setPid(newRowId);
}
#Test
public void addNewPatient() throws Exception {
boolean pin = false;
if (0 != newRowId) {
pin = true;
}
assertTrue("addNewPatient is not true", pin);
}
use the annotation #Before.
like:
public class HTest {
public static Integer i;
#Before
public void before(){
i = 10;
}
#Test
public void print() {
System.out.println(i);
}
}
This before method will be executed before print and i will be Initialized.

Getting "cannot find symbol" error while using static methods

I have really simple code, I have deleted odd code.
So this my class, one of his method is static and I would like to use it later in Main class:
public class TradeInformationReader {
private static String tradeType = "FX_SPOT";
public static double tradePrice = -1;
private double price;
public static int setTradeInformation(String path_to_file) {
return 1;
}
}
And here how I trying to call this last method:
public class Main {
public static int main(String[] args) {
String path_to_file = "D:\\1.txt";
if (0 > TradeInformationReader.setTradeInformation(path_to_file)) {
return -1;
}
return 1;
}
}
I read many posts with a similar issue, but couldn't find a solution. Everything looks fine to me. IDE doesn't show any mistakes and I'm trying just to call static method setTradeInformation, why it does not recognize it (cannot find symbol method setTradeInformation)? Any ideas? I will really appreciate your help.
Your main is not a valid main, so I guess your IDE cannot find a launching class. This should be
public static void main(String[] args)
First you have to put TradeInformationReader class in a seperate file called : TradeInformationReader.java
as follows : `
public class TradeInformationReader {
private static String tradeType = "FX_SPOT";
public static double tradePrice = -1;
private double price;
public static int setTradeInformation(String path_to_file) {
//integer to identify whether the file is found or not 1 if found and 0 if not
int isFileFound = 1;
// the code required to get the file and modify the state of the of isFileFound variable
return isFileFound;
}
}
`
then the main class should have void return type and should be in a file that has the same name as the Main Class as follows:
public class firstApp {
public static void main(String[] args) {
String path_to_file = "D:\\1.txt";
if (0 > TradeInformationReader.setTradeInformation(path_to_file)) {
System.out.println("File not found");
}
}
}
`

Setting up a test system with "real data"

So right now I'm using JUnit 4 and in the #BeforeClass methods I setup everything needed to reset the user schema or to prepare sample data.
Now, it's not that I don't like this approach but I found it quite frustrating for the following reason:
I'm using the Parameterized annotation to run the very same tests with different input data. Parameterized doesn't work on #BeforeClass because #BeforeClass works with a static method.
This means I have to replicate tests if I want to keep the #BeforeClass logic. I can't use #After and #Before because those will happen after every test and it would be an overhead.
I was thinking I could refactor this Unit Tests in the sense that I'll write an abstract class that handles the test and a subclass for every group parameters I want to try so that I can have the test code written only once.
I'm hoping you can suggest a cleaner option with the following starting point: the use of #Parameterized, the need to run the "database" method only once per parameter group.
EDIT:
this is an example of my class without the BeforeClass
RunWith(LabelledParameterized.class)
public class TestCreateCampaign extends AbstractTestSubscriberCampaign {
public TestCreateCampaign(String label, String apiKey, String userKey,
int customerId) {
super(label, apiKey, userKey, customerId);
}
#Before
public void setUp() throws Exception {
super.setUp();
}
#After
public void tearDown() throws Exception {
super.tearDown();
}
#Parameters
public static Collection<Object[]> generatedData() {
return DataProvider.generatedCorrectSubscriberData();
}
#Test
public void testCreateEmailCampaignBothTriggered() {
// TEST
}
#Test
public void testCreateTextCampaignTriggered() {
// TEST
}
#Test
public void testCreateTextCampaignTest() {
// TEST
}
// Other Tests
}
This depends on how you want to set up your classes, but you can use a ClassRule for this. This does the same job as a TestRule, but it runs once for each class, rather than each test. This can be combined with Parameterized and TestRule, such as:
#RunWith(Parameterized.class)
public class TestCreateCampaign {
#ClassRule
public static ExternalResource beforeAfterClass = new ExternalResource() {
#Override
protected void before() throws Throwable {
System.out.println("before each class");
}
#Override
protected void after() {
System.out.println("after each class");
}
};
#Rule
public ExternalResource beforeAfter = new ExternalResource() {
#Override
protected void before() throws Throwable {
System.out.println("before each test");
}
#Override
protected void after() {
System.out.println("after each test");
}
};
#Parameters(name = "{index}: fib({0})={1}")
public static Iterable<Object[]> data() {
return Arrays.asList(new Object[][] { { 3, 0 }, { 4, 1 } });
}
private int fInput;
private int fExpected;
public TestCreateCampaign(int input, int expected) {
fInput = input;
fExpected = expected;
}
#Test
public void test1() {
System.out.println("test1 fInput=" + fInput);
}
}
This produces the following output:
before each class
before each test
test1 3
after each test
before each test
test1 4
after each test
after each class
This seems to be what you're looking for. To cut down on the amount of duplication, you can of course define beforeAfterClass and beforeAfter in a separate java class.
These are available in JUnit 4.9+.
What about calling your setup method from the constructor of your parameterized test class?
Edit:
OK, do I don't know of anything that does this automatically, but I think you could code up a Rule to do it. You could either implement a Rule from scratch of extend ExternalResource. Here is what I think it would do.
The constructor would take an instance of the test class and an ExternalResource instance.
In the constructor it would find the list of methods that contain the #Test annotation a get a count. It would set an iteration count to 0.
In the before method it would increment the iteration count and if it is 1 after increment (or 0 before) it would invoke the before method on the passed ExternalResource.
In the after method it would check to see if the iteration count was equal to the number of tests and if so call the after method on the passed ExternalResource.
You might need to use a different callback class / interface and ExternalResource since the before and after methods are protected. If you really wanted to be cool, you would define your own BeforeParameters and AfterParameter annotations in your rule and it would look for those methods in the passed instance.
If you develop this please post it or submit it to JUnit for inclusion.
Here is what I came up with, not as nice as I would like:
#RunWith(Parameterized.class)
public class TestExample {
private interface BeforeAfter {
void before();
void after();
}
public static class Resource extends ExternalResource {
private final int count;
private final BeforeAfter ba;
private int iteration = 0;
Resource(Object instance, BeforeAfter ba) {
int localCount = 0;
for (Method method : instance.getClass().getMethods()) {
if (method.getAnnotation(Test.class) != null) {
localCount++;
}
}
this.count = localCount;
this.ba = ba;
}
#Override
protected void before() throws Throwable {
if (iteration == 0) {
ba.before();
}
iteration++;
}
#Override
protected void after() {
if (iteration == count) {
ba.after();
iteration = 0;
}
}
}
#Parameters
public static Iterable<Object[]> data() {
return Arrays.asList(new Object[][] { { 3, 0 }, { 4, 1 } });
}
#Rule
public static Resource resource = new Resource(new TestExample(0, 0), new BeforeAfter() {
#Override
public void before() {
System.out.println("setup");
}
#Override
public void after() {
System.out.println("cleanup");
}
});
private int fInput;
private int fExpected;
public TestExample(int input, int expected) {
// System.out.println("Constructor invoked" + fInput);
fInput = input;
fExpected = expected;
}
#Test
public void test1() {
System.out.println("test1 fInput=" + fInput);
}
#Test
public void test2() {
System.out.println("test2 fInput=" + fInput);
}
}
Resulted in:
setup
test1 fInput=3
test2 fInput=3
cleanup
setup
test1 fInput=4
test2 fInput=4
cleanup
See How to load DBUnit test data once per case with Spring Test for a way of initialising your test data only once per test run.

Junit testing for a boolean method

I have problem writing a testcase to this method below: EvenNum(double)
public class OddEven {
/**
* #param args
*/
public boolean evenNum(double num)
{
if(num%2 == 0)
{
System.out.print(true);
return true;
}
else
{
System.out.print(false);
return false;
}
}
This is the testcase I wrote but I think I have an inheritance problem or a logical problem in this test case. Should be a very simple one but can't figure out. Here is the code I wrote:
import static org.junit.Assert.*;
import org.junit.Test;
public class OddEvenTest {
#Test
public void testEvenNum() {
boolean ans = true;
boolean val;
double num= 6;
val = OddEven.EvenNum(num) // cant inherit the method dont know why???
assertEquals(ans,val);
}
}
You have a number of issues:
you are attempting to call a non-static method statically
method names in java are case sensitive and you've mixed up the case.
I corrected some things for you and just verified the code below:
OddEven.java:
public class OddEven {
public boolean evenNum(double num)
{
if(num%2 == 0)
{
System.out.print(true);
return true;
}
else
{
System.out.print(false);
return false;
}
}
}
OddEvenTest.java
import static org.junit.Assert.*;
import org.junit.Test;
public class OddEvenTest {
#Test
public void testEvenNum() {
boolean ans = true;
boolean val;
double num = 6;
OddEven oddEven = new OddEven();
val = oddEven.evenNum(num);
assertEquals(ans,val);
}
}
Assuming the calls to System.out.println() in OddEven are strictly for debugging, the whole thing could be collapsed down to:
OddEven.java
public class OddEven {
public boolean evenNum(double num) {
return num%2 == 0;
}
}
OddEvenTest.java
import static org.junit.Assert.*;
import org.junit.Test;
public class OddEvenTest {
#Test
public void testEvenNum() {
OddEven oddEven = new OddEven();
assertTrue(oddEven.evenNum(6));
assertFalse(oddEven.evenNum(5));
}
}
The code is now shorter and the unit test even covers an odd case for good measure.
Two things :
You are invoking a non-static method statically. The method should be declared static:
public static boolean evenNum(double num) {
}
You didn't type the name of the method correctly. Look closely. Also consider renaming it something more readable like, isEven(...)
This seems like testing gone mad to me, and programming gone mad too. All the method does is evaluate num % 2 == 0. You may as well just code that everywhere required and throw away both the method and its tests. If you must keep the method, it relies on a mathematical identity, you don't need to test those. You may as well test 1+1==2.

Categories

Resources