【问题标题】:how to assert true for two different values in a for loop?如何在 for 循环中为两个不同的值断言 true?
【发布时间】:2013-01-03 08:20:59
【问题描述】:

我在 mongo 中有需要验证的数据:

"items" : [
            {
                    "item" : 0,
            },
            {
                    "item" : 1,
            }
    ],

我的代码中有一个 for 循环:

for (Object a : getItems()){
 HashMap<?, ?> b = (HashMap<?, ?>)a;
 assertTrue(b.containsValue(0));
}

这里有一个问题,因为 items 的值为 1 和 0,如果它也包含 1,我需要为第二次迭代断言。如何验证 1 和 0 是否都存在?

有没有其他的断言方法可以做到这一点?

已编辑:

List lt1 = new ArrayList();
lt1.add(0);
lt1.add(1);
List lt2 = new ArrayList();

for (Object a : getItems()){
 HashMap b = (HashMap)a;
 lt2.add(b.get("item");
}

assertThat(lt2, hasItems(lt1));

这会在 assertThat.. 行引发调用目标异常。 此外,JUNIT 显示一个断言错误,如下所示:

Expected : A collection of [0,1]
Got : [0,1]

【问题讨论】:

  • 它取决于创建哈希映射的热度。您可以使用哈希映射,其中键映射到列表,然后断言列表同时包含 0 和 1
  • 由于键是相同的,我会认为最后一个值替换了前一个值。我建议您使用“项目”列表而不是地图(或使键唯一)
  • 是的,完全正确。而且我不能使键唯一。我可以创建一个列表并添加 0 和 1。但是,如何在一次只取 1 个值的 for 循环中验证它们?
  • 我想我成功了!感谢@PeterLawrey 的帮助

标签: java mongodb junit assert


【解决方案1】:

由于您使用的是 JUnit,as of v4.4 库可以使用 hamcrest 匹配器库,它提供了丰富的 DSL 来构建测试表达式。这意味着您可以完全删除循环并编写一个断言,测试所有预期值是否存在。

例如,hamcrest 有一个内置函数 hasItems()(v1.3.RC2 的文档链接,但 v1.3 已发布 - 抱歉找不到最新链接)。

import java.util.List;
import java.util.Arrays;
import static org.hamcrest.Matchers.hasItems;
import static org.junit.Assert.assertThat;

@Test
public void bothValuesShouldBePresent() {
    List<Integer> itemValues = Arrays.asList(new Integer[]{ 0, 1, 2, 3 });
    Integer[] expected = { 0, 1 };
    assertThat(itemValues, hasItems(expected));
}

当然,这假设您可以修改您的 getItems() 方法以返回一个简单的 List&lt;Integer&gt;

最后,根据您使用的 JUnit 版本,hamcrest 可能捆绑也可能不捆绑。 JUnit 在 v4.4 和 v4.10 之间内联 hamcrest-core。因为它只是hamcrest-core,所以我在我的项目中明确添加了hamcrest-all 依赖项。从 JUnit v4.11 起,hamcrest 不再内联(恕我直言),因此如果您想使用匹配器,您将始终需要显式添加依赖项。

另外,这是一个关于 hamcrest 集合匹配的useful blog post

编辑:

我试图考虑您的getItems() 可能会返回什么,这是一个更新的测试示例。请注意,您需要将 expected 值转换为数组 - 请参阅 Why doesn't this code attempting to use Hamcrest's hasItems compile?

@Test
public void bothValuesShouldBePresent() {
    List lt1 = new ArrayList();
    lt1.add(0);
    lt1.add(1);
    List lt2 = new ArrayList();

    List fakeGetItems = new ArrayList() {{ add(new HashMap<String, Integer>() {{ put("item", 0); }}); add(new HashMap<String, Integer>() {{ put("item", 1); }} ); }};

    for (Object a : fakeGetItems) {
     HashMap b = (HashMap)a;
     lt2.add(b.get("item"));
    }

    assertThat(lt2, hasItems(lt1.toArray(new Integer[lt1.size()])));
}

【讨论】:

  • 谢谢。我用两个列表尝试了这个。列表 a 具有 [0, 1] 和列表 b 具有相同的值。但是,当我执行assertThat(a, hasItems(b)) 时,我得到一个调用目标异常。有什么解决办法吗?
  • 没有可能难以回答的确切错误和源代码。您可以添加异常的前几行作为评论吗?另外,您能否在我对您的代码的回答中添加简单测试,看看是否有效?
  • 我已经用编辑下的新代码编辑了我自己的问题。你能看一下吗?
  • 我已经用另一个示例更新了我的答案,希望对您有所帮助。我无法重现您看到的确切错误,因为我无权访问 getItems() 函数。
【解决方案2】:

使用AssertJ 会更容易

@Test
public void bothValuesShouldBePresent1()  {
  List<Integer> lt2 = Arrays.asList(0, 1);
  List<Integer> lt1 = Arrays.asList(0, 1);
  assertThat(lt2).containsExactlyElementsOf(lt1);
}

@Test
public void bothValuesShouldBePresent2()  {
  List<Integer> lt2 = Arrays.asList(0, 1);
  assertThat(lt2).containsExactly(0, 1);
}

@Test
public void bothValuesShouldBePresent3()  {
  List<MyItem> lt2 = Arrays.asList(new MyItem(0), new MyItem(1));
  assertThat(extractProperty("item").from(lt2))
      .containsExactly(0, 1);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 2015-07-07
    • 2016-12-03
    相关资源
    最近更新 更多