【问题标题】:UnitTest a helper class (not controller, not service etc.)UnitTest 一个助手类(不是控制器,不是服务等)
【发布时间】:2018-02-07 08:44:07
【问题描述】:

UnitTest 一个辅助类(不是控制器,不是服务,

一开始我需要说我阅读了很多帖子,例如: When should I mock? 或者 Should I mock all the dependencies when unit testing?

我还阅读了一篇关于“如何在 SPRING 中测试控制器”或“如何测试服务层”的文章。

但现在我想为我的“控制器”测试一个“助手类”(我不确定是否有区别)。

我的实体类如下所示:

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

让我们看看我要测试的方法:

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<>()));
}

就像你注意到的,这里的方法有两个参数,一个是地图(Integer 和 TimeForm)和时间。

这意味着要进行此测试,我需要创建时间的 testObject,我需要设置方法中的所有字段? 例如

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

就像您可以注意到时间需要评论,cmets 需要帖子,帖子需要主题。 这意味着我需要创建所有这些? 你能解释一下我做错了什么吗?

@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;
    }   
}

当我使用像 upper 这样的示例数据运行测试时,我有一个 java.lang.NullPointerException。

这是一个错误堆栈跟踪:

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

更新: 以这种方式编辑我的 testObject 方法后测试通过:

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;
}

但我仍然不确定这是否是正确的方式(如果 some1 可以在评论中确认这是 100% 正确的方式,我将不胜感激。)

【问题讨论】:

  • NPE 在哪一行。堆栈跟踪在哪里

标签: java spring unit-testing


【解决方案1】:

这意味着我需要创建所有这些?

是的。

你能解释一下我做错了什么吗?

从概念上讲?什么都没有。

您的参数Time 看起来像一个数据传输对象。这有点特殊,因此我们通常不会对他们应用 demeter 法则(不要和陌生人说话!)。

另一方面,您可能想要应用 信息隐藏(因此也需要 LoD,以便通过添加 委托方法来避免“链式破坏” Time 类。

然后Time 有点“混合”,您将创建它的模拟(这不适用于“纯”DTO,并且不需要配置 Timeobject 的所有依赖项。 .

【讨论】:

  • 哦,我想我现在明白了。我需要模拟 Time 并将其作为 generateSimpleTestObject 的参数传递给方法。我说的对吗?
  • 我添加了摘要。在您确认“这是一种正确的方法”之后,我当然会接受您的回答。
  • @degath "我需要模拟 Time 并将其作为 generateSimpleTestObject 的参数传递给方法" 如果您添加了 delecation 方法,您只需模拟 Time 参数 并删除了Time 的(复杂)属性的getters。你不要模拟纯 DTO
猜你喜欢
  • 2020-10-11
  • 1970-01-01
  • 1970-01-01
  • 2013-02-08
  • 2016-04-07
  • 1970-01-01
  • 2018-07-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多