Using dummy objects
In movies, sometimes a double doesn't perform anything; they just appear on the screen. One such instance would be standing in a crowded place where the real actor cannot go, such as watching a soccer match or tennis match. It will be very risky for the real actor to go to a full house, but the movie's script needs it.
Likewise, a dummy object is passed as a mandatory parameter object. A dummy object is not directly used in the test or code under test, but it is required for the creation of another object required in the code under test. Dummy objects are analogous to null objects, but a dummy object is not used by the code under test. Null objects (as in the pattern) are used in the code under test and are actively interacted with, but they just produce zero behavior. If they weren't used, you'd just use an actual null value. The following steps describe the usage of dummy objects:
Note
In this book, we will write the code and JUnit tests in the Eclipse editor. You can download Eclipse from the following URL:
- Launch Eclipse and create a workspace,
\PacktPub\Mockito_3605OS\
; we'll refer to it as<work_space>
in the next steps/chapters. - We'll create an examination grade system. The program will analyze the aggregate of all the subjects and determine the grade of a student. Create a Java project named
3605OS_TestDoubles
. Add anenum Grades
field to represent a student's grades:package com.packt.testdoubles.dummy; public enum Grades { Excellent, VeryGood, Good, Average, Poor; }
Tip
Downloading the example code
You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.
We'll use
src
as our source code's source folder andtest
as our test code's source folder. All Java files for this example will be created under thecom.packt.testdoubles.dummy
package. - Create a
Student
class to uniquely identify a student:public class Student { private final String roleNumber; private final String name; public Student(String roleNumber, String name) { this.roleNumber = roleNumber; this.name = name; } //setters are ignored }
- Create a
Marks
class to represent the marks of a student:public class Marks { private final Student student; private final String subjectId; private final BigDecimal marks; public Marks(Student student, String subjectId, BigDecimal marks) { this.student = student; this.subjectId = subjectId; this.marks = marks; } //getters methods go here }
Note that the
Marks
constructor accepts aStudent
object to represent the marks of a student. So, aStudent
object is needed to create aMarks
object. - Create a
Teacher
class to generate a student's grades:public class Teacher { public Grades generateGrade(List<Marks> marksList) { BigDecimal aggregate = BigDecimal.ZERO; for (Marks mark : marksList) { aggregate = aggregate.add(mark.getMarks()); } BigDecimal percentage = calculatePercent(aggregate, marksList.size()); if (percentage.compareTo(new BigDecimal("90.00")) > 0) { return Grades.Excellent; } if (percentage.compareTo(new BigDecimal("75.00")) > 0) { return Grades.VeryGood; } if (percentage.compareTo(new BigDecimal("60.00")) > 0) { return Grades.Good; } if (percentage.compareTo(new BigDecimal("40.00")) > 0) { return Grades.Average; } return Grades.Poor; } private BigDecimal calculatePercent(BigDecimal aggregate,int numberOfSubjects) { BigDecimal percent = new BigDecimal(aggregate.doubleValue()/ numberOfSubjects); return percent; }
- Create a
DummyStudent
class and extend theStudent
class. This is the dummy object. A dummy object will be the one that is not the real implementation and provides zero functionality or values. TheDummyStudent
class throws a runtime exception from all the methods. The following is the body of theDummyStudent
class:public class DummyStudent extends Student { protected DummyStudent() { super(null, null); } public String getRoleNumber() { throw new RuntimeException("Dummy student"); } public String getName() { throw new RuntimeException("Dummy student"); } }
Note that the constructor passes
NULL
to the super constructor and throws a runtime exception from thegetRoleNumber()
andgetName()
methods. - Create a JUnit test to verify our assumption that when a student gets more than 75 percent (but less than 90 percent) in aggregate, then the teacher generates the grade as
VeryGood
, creates aDummyStudent
object, and passes it asStudent
to theMarks
constructor:public class TeacherTest { @Test public void when_marks_above_seventy_five_percent_returns_very_good() { DummyStudent dummyStudent = new DummyStudent(); Marks inEnglish = new Marks(dummyStudent, "English002", new BigDecimal("81.00")); Marks inMath = new Marks(dummyStudent, "Math005", new BigDecimal("97.00")); Marks inHistory = new Marks(dummyStudent, "History007, new BigDecimal("79.00")); List<Marks> marks = Arrays.asList(inHistory, inMaths, inEnglish); Grades grade = new Teacher().generateGrade(marks); assertEquals(Grades.VeryGood, grade); } }
Note that a
DummyStudent
object is created and passed to all the threeMarks
objects, as theMarks
constructor needs aStudent
object. ThisdummyStudent
object is not used in theTeacher
class or test method, but it is necessary for theMarks
object. ThedummyStudent
object shown in the preceding example is a dummy object.