Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Repeating code in JUnit tests

Is it "bad" to duplicate code in the testclass? As you see I add drivingrecords to the drivinglog to have something to test on in multiple methods. Is it better to extract this to a private helper method or is it better for clarity to keep it like it is? What do you do in such cases?

@Test
public void shouldRemoveAllDrivingRecords() {
    Duration duration1 = new Duration(1, 30, 45);
    Duration duration2 = new Duration(2, 50, 12);

    DrivingRecord drivingRecord1 = new DrivingRecord(230.0, duration1, "This was a long trip");
    DrivingRecord drivingRecord2 = new DrivingRecord(300.0, duration2, "This trip is even longer.");

    drivingLog.addDrivingRecord(drivingRecord1);
    drivingLog.addDrivingRecord(drivingRecord2);

    drivingLog.removeAllDrivingLogs();

    assertEquals(0, drivingLog.numberOfDrivingRecords());
}

@Test
public void shouldSumTheDistanceDriven() {
    Duration duration1 = new Duration(1, 30, 45);
    Duration duration2 = new Duration(2, 50, 12);

    DrivingRecord drivingRecord1 = new DrivingRecord(230.0, duration1, "This was a long trip");
    DrivingRecord drivingRecord2 = new DrivingRecord(300.0, duration2, "This trip is even longer.");

    drivingLog.addDrivingRecord(drivingRecord1);
    drivingLog.addDrivingRecord(drivingRecord2);

    double expectedDistanceDriven = drivingRecord1.getDistance() + drivingRecord2.getDistance();
    double totalDistanceDriven = drivingLog.getDistanceDriven();

    assertEquals(expectedDistanceDriven, totalDistanceDriven, 0.1);
}
like image 458
LuckyLuke Avatar asked Nov 28 '22 14:11

LuckyLuke


2 Answers

You can annotate a method with @org.junit.Before and initialize the variables in that method:

public class DrivingLogTest { 
     //suposing DrivingLog class...
     private DrivingLog drivingLog;

     private Duration duration1;
     private Duration duration2;

     private DrivingRecord drivingRecord1;
     private DrivingRecord drivingRecord2;


    @Before 
    public void setUp() { 
       drivingLog=new DrivingLog();
       duration1 = new Duration(1, 30, 45);
       duration2 = new Duration(2, 50, 12);

       drivingRecord1 = new DrivingRecord(230.0, duration1, "This was a long trip");
       drivingRecord2 = new DrivingRecord(300.0, duration2, "This trip is even longer.");

       drivingLog.addDrivingRecord(drivingRecord1);
       drivingLog.addDrivingRecord(drivingRecord2);

    }


    @Test
    public void shouldRemoveAllDrivingRecords() {

       drivingLog.removeAllDrivingLogs();

       assertEquals(0, drivingLog.numberOfDrivingRecords());
    }

    @Test
    public void shouldSumTheDistanceDriven() {

       double expectedDistanceDriven = drivingRecord1.getDistance() +  drivingRecord2.getDistance();
       double totalDistanceDriven = drivingLog.getDistanceDriven();

       assertEquals(expectedDistanceDriven, totalDistanceDriven, 0.1);
    }
}
like image 173
Tomas Narros Avatar answered Dec 12 '22 14:12

Tomas Narros


I dare to disagree with most answers, and to me test code is not the same as production code. Sure, test code deserves the same care and attention as production code, because it's part of the overall development effort, but they differ in nature. I will not repeat myself, and rather point to another answer of mine: Is it OK to copy past unit test when logic is the same.

That said, repeating the creation of test data is bad. What is better is to think of a data set that is carefully created for testing, and support testing the most cases. This data set can be created in the setUp method. There can be several test data sets, covering variations of the business rules, if necessary. Creating useful test data sets is not easy, but it's worth spending some time on it. Also, test data could be loaded from JSON or so. In some case, it's easier to maintain.

Unit tests should normally not depend on each other. But frequently, test case do depend on each other. For instance, to test a list, one want to test that add() works, that isEmpty() works, that remove() works. Testing remove() assumes that add() works. For such scenario, you can use JExample, a unit testing framework with which you can "chain" tests.

like image 20
ewernli Avatar answered Dec 12 '22 13:12

ewernli