自动化测试之—Hamcrest匹配器

xiaoxiao2021-02-27  202

自动化测试之—Hamcrest匹配器

本来计划要写一点Espresso方面知识的,但是想到Espresso中好多控件或者断言都是使用Hamcrest匹配器,另一方面则是Hamcrest匹配器相比JUnit的Assert则显得更加优雅、轻便,更容易阅读。

自动化测试之Hamcrest匹配器 简述常用API自定义匹配器 实现BaseMatcherT接口实现TypeSafeMatcherT接口

简述

Hamcrest是用于编写匹配器对象的框架,允许以声明方式定义“匹配”规则。有许多情况下匹配器是不可估量的,例如UI验证或数据过滤,但是在编写灵活测试的领域中,匹配器反而是最常用的。

Hamcrest还是相对比较简单的,API也相对比较少,就从一个小例子说起吧。

假如要你要测试一个集合中是否包含三个元素中的一个,如果包含则断言真,否则为假。把集合的初始化放在@Before中,则用JUnit的Assert断言写法如下:

import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.util.ArrayList; import java.util.List; import static org.junit.Assert.assertTrue; /** * Created by star on 2017/8/3. */ @RunWith(JUnit4.class) public class HamcrestTest { private List<String> hamcrestTestList; @Before public void setUp() { hamcrestTestList = new ArrayList<>(); hamcrestTestList.add("first element"); hamcrestTestList.add("second element"); hamcrestTestList.add("third element"); } @Test public void assertWithJunitTest() { assertTrue(hamcrestTestList.contains("first element") || hamcrestTestList.contains("second element") || hamcrestTestList.contains("third element")); } }

assertWithJunitTest方法本身并难以理解,但是你第一眼看到它很可能不太明白它是做什么的,而且代码也不简练,而Hamcrest则正是为了简化断言,可以构建测试表达式的匹配器库。Hamcrest的书写方法如下:

import static org.hamcrest.CoreMatchers.anyOf; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.hasItem; ... @Test public void assertWithHamcrestTest(){ assertThat(hamcrestTestList, hasItem(anyOf(equalTo("first element"), equalTo("second element"), equalTo("third element")))); }

常用API

hamcrest的匹配器都看起来很好理解,并且还提供了自定义匹配器的接口,可以满足编写代码的需要。主要的API接口有如下:

核心 anything -绝对匹配,无论什么情况下都会匹配成功;describedAs -添加自定义失败描述is -是否的意思,仅用来改善断言语句的可读性;逻辑 allOf -检查是否包含所有的匹配器,相当于与(&&);anyOf -检查是否包含匹配器中的一个,相当于(||);not - 检查是否与匹配器相反,相当于非(!);对象 equalTo -检查两个对象是否相等;hasToString - 检查Object.toString;instanceOf,isCompatibleType -检查对象是否是兼容类型;notNullValue,nullValue -检查是否是null值;sameInstance -检查对象是否是相同的类型;Beans hasProperty -检查对象是否有某种属性;集合 array -检查array的元素是否和匹配器描述的相同;hasEntry,hasKey,hasValue -测试给定的Map是否有特定的实体、键或者值;hasItem,hasItems -测试集合是否有一个或者多个元素;hasItemInArray -测试数组中是否有某一元素;数字 closeTo给定的数字是否接近于给定的值;greaterThan,greaterThanOrEqualTo,lessThan,lessThanOrEqualTo -给定的数字是否大于、大于等于、小于、小于等于给定的值;文本 equalToIgnoringCase -检查给定的字符串是否与另一字符串在忽略大小写的情况下相同;equalToIgnoringWhiteSpace -检查给定的字符串是否与另一字符串在忽略空格的情况下相同;containsString -检查给定的字符串是否包含某一字符串;endsWith -检查给定的字符串是否以某一字符串结尾;startsWith -检查给定的字符串是否以某一字符串开头;

这些匹配器除了单独使用外,还可以组合使用,提供更佳精确的匹配。例如

自定义匹配器

hamcrest除了可以使用上述匹配器以外,还可以自己编写合适的匹配器,更好的进行测试。自定义匹配器需要实现Mather接口和一个适当的工厂方法。自定义匹配器一方面可以达到合适的匹配,另一方面也可以简化断言语句。

要想定义自定义匹配器,则需要实现BaseMatcher<T>或者TypeSafeMatcher<T>,需要在build.gradle文件中dependencies闭包中引入对应的包:

dependencies { androidTestImplementation 'org.hamcrest:hamcrest-core:1.3' }

自定义匹配器有以下两种实现方法:

实现BaseMatcher<T>接口

如果实现了BaseMatcher<T>,那么需要重写matches方法,matches方法内部实现我们的逻辑,即要满足什么条件时匹配器将匹配各种条件,并确定是否匹配成功。比如如果要实现自定义匹配器,判断给定的字符串是否以ham开头,并且以java结尾,则自定义匹配器实现方式如下:

import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Factory; import org.hamcrest.Matcher; /** * Created by star on 2017/8/4. */ public class IsExceptedStringMatcher extends BaseMatcher<String> { @Factory public static <T> Matcher<String> isExceptedString() { return new IsExceptedStringMatcher(); } @Override public boolean matches(Object item) { String str = (String) item; if (str != null && str.length() >= 7 && str.startsWith("ham") && str.endsWith("java")) { return true; } return false; } @Override public void describeTo(Description description) { description.appendText("a string that start with \"ham\" and end with \"java\""); } }

之后就可以在断言中直接使用自定义匹配器:

@Test(expected = AssertionError.class) public void isExceptedStringTest(){ String str="hamcrestjava"; assertThat(str,isExceptedString()); str=null; assertThat(str,isExceptedString()); }

实现TypeSafeMatcher<T>接口

如果实现了TypeSafeMatcher <T>,那么需要重写matchesSafely方法,

protected boolean matchesSafely(T item)

matchesSafely方法内部同样实现我们的逻辑,该方法绝不能接受一个null对象,它总会接受一个类型为T的参数,该参数已被检查是否为null且永远不能为null。如果我们要在自定义匹配器内部进行是否为null检查,则要继续实现BaseMatcher<T>接口,如果要自定义一个密码检查的匹配器,要求密码必须包含1个特殊符号(!、”、#、$、%、&、’、(、)、*、+、-、.、/)和1个数字,并且密码长度至少为6,则自定义匹配器实现方式如下:

import org.hamcrest.Description; import org.hamcrest.Factory; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; /** * Created by star on 2017/8/4. */ public class IsStrongPassword extends TypeSafeMatcher<String> { @Factory public static <T> Matcher<String> isStrongPassword() { return new IsStrongPassword(); } @Override protected boolean matchesSafely(String item) { if (containsSymbol(item) && containsDigit(item) && item.length() >= 6) { return true; } return false; } private boolean containsDigit(String password) { for (char ch : password.toCharArray()) { if (Character.isDigit(ch)) { return true; } } return false; } private boolean containsSymbol(String password) { for (char ch : password.toCharArray()) { if ((int) ch >= 33 && (int) ch <= 47) { return true; } } return false; } @Override public void describeTo(Description description) { description.appendText("a string which a strong password"); } }

接下来你同样可以在测试代码中使用如下的方式使用该匹配器:

@Test(expected = AssertionError.class) public void IsStrongPasswordTest() { String password; password = "!1s2dxs"; assertThat(password, isStrongPassword()); password = "123dsda"; assertThat(password, isStrongPassword()); }

Over…如果有不对的地方欢迎批评指正 :)

转载请注明原文地址: https://www.6miu.com/read-9842.html

最新回复(0)