0

UnitTest a helper class (not controller, not service,

At the begin I need to say that I read a lot of posts for example: When should I mock? or Should I mock all the dependencies when unit testing?

I also read an article about "How to test Controller in SPRING" or "How to test service Layer".

But right now I want to test a "Helper class" for my "controller" (I'm not sure if there is a difference).

My entities classes looks like this:

topics 1:n posts  1:n comments 1:n time.

lets look at the method I want to test:

void parseToModel(Map<Integer, TimeForm> mapToTime, Time time) {
    mapToTime.putIfAbsent(time.getComment().getId(), new TimeForm(time.getComment().getPost().getTopic().getName(),
        time.getComment().getPost().getName(),
        time.getComment().getName(),
        new ArrayList<>()));
}

Like you notice here method have two parameters one is a map (Integer and TimeForm) and time.

It means that to make this test I need to create testObject of Time where I need to set all fields from the method? e.g.

Time time = new Time();
time.getComment().setId();
time.getComment().getPost().getTopic().setName();
time.getComment().getPost().setName();
time.getComment().setName();
return time;

Like you can notice times need comment, comments need a post, and posts need a topic. This means I need to create all of them? Can you explain me what I'm doing wrong?

@RunWith(MockitoJUnitRunner.class)
public class helperTest{
    //given
    final TimeController timeController = new TimeController(Mockito.mock(TimeService.class));
    Map<Integer, TimeForm> testMap = new HashMap<>();
    Time testObject = generateSimpleTestObject();

    @Test
    public void parse() {
    //when
    timeController.parseToModel(testMap, testObject);
    //then
    Assert.assertEquals(testMap.size(), 1);
    }

    Time generateTestObj(){
    Time testObj = new Time();
    time.getComment().setId("5");
    time.getComment().getPost().getTopic().setName("TestingJava");
    time.getComment().getPost().setName("Unit test.");
    time.getComment().setName("Is it so hard?");
    return time;
    }   
}

When I run my test with example data like upper I have a java.lang.NullPointerException.

This is an error stacktrace:

java.lang.NullPointerException at com.timeproject.time.view.HelperTest.generateSimpleTestObject(HelperTest.java:40) at com.timeproject.time.view.HelperTest.(HelperTest.java:26) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:217) at org.junit.runners.BlockJUnit4ClassRunner$1.runReflectiveCall(BlockJUnit4ClassRunner.java:266) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37) at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Update: Test passed after editing my testObject method that way:

Time generateSimpleTimeTestObject() {
    Time time = new Time();
    Comment comment = new Comment();
    Project project = new Project();
    Topic topic = new Topic();

    time.setComment(comment);
    time.getComment().setPost(post);
    time.getComment().getPost().setTopic(topic);

    time.getComment().setId(999);
    time.getComment().getPost().getTopic().setName("Topic name");
    time.getComment().getPost().setName("Post name");
    time.getComment().setName("Comment name");
    return time;
}

But I'm still not sure if its a right way (if some1 could confirm in a comment it's a 100% right way to do it I would've be grateful.)

degath
  • 1,157
  • 2
  • 19
  • 43

1 Answers1

1

This means I need to create all of them?

Yes.

Can you explain me what I'm doing wrong?

conceptually? Nothing.

Your Parameter Time looks like a data transfer object. This is somewhat special so that we usually do not apply the law of demeter (Don't talk to strangers!) to them.

On the other hand you might want to aplly information hiding (and in consequence LoD too so that you avoid the "chain wracking" by adding delegation methods to the Time class.

Then Time is somewhat of a "hybrit" and you would create a mock of it (which wi not do for "pure" DTOs, and do not need to configure all the dependencies of a Timeobject...

Timothy Truckle
  • 12,232
  • 2
  • 22
  • 44
  • Ohhh, I think I understand now. I need to mock Time and pass it to the method as parameter of generateSimpleTestObject. Am I right? – degath Feb 07 '18 at 09:24
  • I added the summary. After your confirmation about "it's a proper way" to do it I'll, of course, accept your answer. – degath Feb 07 '18 at 10:11
  • @degath *"I need to mock Time and pass it to the method as parameter of generateSimpleTestObject"* you only mock `Time` parameter if you added the *delecation methods* and removed the *getters* to the (complex) properties of `Time`. You *don't mock pure DTOs*! – Timothy Truckle Feb 07 '18 at 11:01