【问题标题】:Test with Easymock for cases testing使用 Easymock 进行案例测试
【发布时间】:2020-01-06 15:59:01
【问题描述】:

我目前正在进行单元测试,我正在尝试创建一个测试来测试单个函数的不同案例。例如,我有以下功能:

public static String foo(Object arg0, Object arg1) {
    String returnValue = null;
    if(arg0.getName() != null && arg0.getId() != null) {
        returnValue = "Value 1";
    } else if (arg1.getName() != null && arg1.getId() != null ) {
        returnValue = "Value 2";
    }
    return returnValue;
}

我想测试以下情况:

  • 案例 1:arg0.getName() == nullarg1.getName() == null
  • 案例 2:arg0.getName() != nullarg0.getId() != nullarg1.getName() == null
  • 案例 3:arg0.getName() == nullarg1.getName() != nullarg1.getId() != null

等等……

我目前的测试是这样的:

public void testFoo() {
    /** Setting up my mocks**/
    Obj arg0 = createMock(Obj.class);
    Obj arg1 = createMock(Obj.class);

    /** Setting my mocks behaviors **/

    // Case 1
    EasyMock.expect(arg0.getName()).andReturn(null);
    EasyMock.expect(arg1.getName()).andReturn(null);

    // Case 2
    EasyMock.expect(arg0.getName()).andReturn("Jack");
    EasyMock.expect(arg0.getId()).andReturn(1);
    EasyMock.expect(arg1.getName()).andReturn(null);

    // Case 3
    EasyMock.expect(arg0.getName()).andReturn(null);
    EasyMock.expect(arg1.getName()).andReturn("Paul");
    EasyMock.expect(arg1.getId()).andReturn(2);

    //End Cases
    EasyMock.replay(arg0_case1, arg0_case2, arg0_case3,

arg1_case1, arg1_case2, arg1_case3);

    /** Testing **/

    // Case 1
    String expectedValue = null;
    String output = foo(arg0, arg1);
    assertEquals(expectedValue, output);

    // Case 2
    expectedValue = "Value 1";
    output = foo(arg0, arg1);
    assertEquals(expectedValue, output);

    // Case 3
    expectedValue = "Value 2";
    output = foo(arg0, arg1);
    assertEquals(expectedValue, output);
}

我在这个测试中遇到的问题是,即使我为每个测试用例设置了我的模拟,似乎设置也没有按照我选择的顺序进行。我尝试添加.once()atLeastOnce(),但即便如此,它还是失败了。

你有这种测试的解决方案吗?也许我应该为每种情况编写不同的测试?


编辑 感谢@swayamraina 的解决方案和对我的代码的一些修改,我找到了一个解决方案。这不是最有效的答案,但它可以完成工作。这是我编辑的代码:

public void testFoo() {
/** Setting my mocks behaviors **/

// Case 1
Obj arg0_case1 = createMock(Obj.class);
Obj arg1_case1 = createMock(Obj.class);
EasyMock.expect(arg0_case1.getName()).andReturn(null).anyTimes();
EasyMock.expect(arg1_case1.getName()).andReturn(null).anyTimes();

// Case 2
Obj arg0_case2 = createMock(Obj.class);
Obj arg1_case2 = createMock(Obj.class);
EasyMock.expect(arg0_case2.getName()).andReturn("Jack").anyTimes();
EasyMock.expect(arg0_case2.getId()).andReturn(1).anyTimes();
EasyMock.expect(arg1_case2.getName()).andReturn(null).anyTimes();

// Case 3
Obj arg0_case3 = createMock(Obj.class);
Obj arg1_case3 = createMock(Obj.class);
EasyMock.expect(arg0_case3.getName()).andReturn(null).anyTimes();
EasyMock.expect(arg1_case3.getName()).andReturn("Paul").anyTimes();
EasyMock.expect(arg1_case3.getId()).andReturn(2).anyTimes();

//End Cases
EasyMock.replay(arg0, arg1);

/** Testing **/

// Case 1
String expectedValue = null;
String output = foo(arg0_case1, arg1_case1);
assertEquals(expectedValue, output);

// Case 2
expectedValue = "Value 1";
output = foo(arg0_case2, arg1_case2);
assertEquals(expectedValue, output);

// Case 3
expectedValue = "Value 2";
output = foo(arg0_case3, arg1_case3);
assertEquals(expectedValue, output);

就像@swayamraina 在其回答中提出的那样,我为每个案例测试创建了不同的模拟,并在每个EasyMock.expect().andReturn() 之后添加了一个.anyTimes(),它运行良好。 我会在这篇文章中更新我可能实施的改进。

【问题讨论】:

  • 绝对为每个测试场景创建一个单元测试方法。由于您至少有 3 个案例,因此您至少有 3 种测试方法(每个案例一个测试)。
  • 感谢您的回答。不幸的是,我有 60 个函数要测试,每次至少要测试 8 个案例。帖子中的函数是一个纯粹的例子,我想让我的测试类尽可能容易理解和简单。这是唯一的解决方案吗?
  • 将单元测试视为您的安全网。我们很少需要对代码进行 100% 的测试覆盖率,但我们需要足够的代码来显示我们的代码按预期工作。只有你能说出多少安全网才能让你的项目不至于崩溃。
  • 无需每次都创建不同的对象。您可以重复使用这些对象并将它们替换为不同的值。请参考我的解决方案。
  • 除此之外,请确定:您真的需要模拟这些对象吗?你不能在你的测试代码中做一个new A(),添加所需的数据,然后将这些对象传递给你的测试代码吗?

标签: java unit-testing junit easymock


【解决方案1】:

以下是更新后的测试用例

@Test
public void test()  {

  A arg0, arg1;

  // Case 1
  arg0 = EasyMock.createMock(A.class);
  arg1 = EasyMock.createMock(A.class);

  // expectations
  EasyMock.expect(arg0.getName()).andReturn(null).once();
  EasyMock.expect(arg1.getName()).andReturn(null).once();
  EasyMock.replay(arg0, arg1);

  // actuals
  String expectedValue = null;
  String output = foo(arg0, arg1);

  // assertions
  Assert.assertEquals(expectedValue, output);


  // Case 2
  arg0 = EasyMock.createMock(A.class);
  arg1 = EasyMock.createMock(A.class);

  // expectations
  EasyMock.expect(arg0.getName()).andReturn("Jack").once();
  EasyMock.expect(arg0.getId()).andReturn(1).once();
  EasyMock.expect(arg1.getName()).andReturn(null).once();
  EasyMock.replay(arg0, arg1);

  // actuals
  expectedValue = "Value 1";
  output = foo(arg0, arg1);

  // assertions
  Assert.assertEquals(expectedValue, output);


  // Case 3
  arg0 = EasyMock.createMock(A.class);
  arg1 = EasyMock.createMock(A.class);

  // expectations
  EasyMock.expect(arg0.getName()).andReturn(null).once();
  EasyMock.expect(arg1.getName()).andReturn("Paul").once();
  EasyMock.expect(arg1.getId()).andReturn(2).once();
  EasyMock.replay(arg0, arg1);

  // actuals
  expectedValue = "Value 2";
  output = foo(arg0, arg1);

  // assertions
  Assert.assertEquals(expectedValue, output);
}



使用的测试类:

class A {
    String name; public String getName() {return  name;} 
    Integer id; public Integer getId(){return id;}
}


注意事项:
您只能重播一次模拟。您需要为每个测试用例创建新的测试对象。在这里,我们首先创建模拟,然后设置期望并重放模拟。最后根据实际值断言。


作为一般流程,我喜欢使用 .描述每个的多个测试用例。
每个测试用例也遵循以下模式

  1. 声明变量
  2. 描述测试用例
  3. 设定期望
  4. 定义结果(实际)
  5. 应用断言

【讨论】:

  • 谢谢!我会试试这个结构,我会告诉你它是否适合我;)
  • 当然,很高兴为您提供帮助。请务必将答案标记为已接受,以供将来遇到类似问题并回答此问题的其他人使用。
  • 我今天早上尝试了这个结构,它不起作用:我尝试了两个案例,由于某种原因,第一个案例通过了,但第二个案例没有。我尝试删除 EasyMock.expect().andReturn() 上的 .once(),但由于我的 foo() 函数的第二次调用,情况 2 似乎失败了。我正在努力
  • 我发布的代码在我的环境中运行良好。
  • 感谢您的回答。我试过了,只有在每个 expect().andReturn() 之后添加 .anyTimes() 才能正常工作。我编辑了我的帖子。再次感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-21
  • 1970-01-01
  • 1970-01-01
  • 2019-10-06
  • 2011-07-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多