Table of contents


Matcher

實作這個Matcher以接受各式各樣格式的參數進行比對。 一般Unit Test的extension framework都會實作自己的Matcher,並且提供Matcher的factory methods或factory class。

Description

透過Descriptionclass讓test results更具可讀性。

在eclipse的static import favorite設定一下幾個factory class即可

    org.hamcrest.Matchers.*

有些method不能直接使用,要給予明確的型別資訊,像這樣

    assertThat(data, Matchers.<MyClass>iterableWithSize(1));

Junit & Hamcrest

Junit目前(4.8.x版)對Hamcrest有相容性的依賴,無法使用Hamcrest 1.1以上的版本,但可以透過引用unit-dep然後把hamcrest-core的dependency結移除

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit-dep</artifactId>
        <version>4.8.2</version>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.hamcrest</groupId>
                <artifactId>hamcrest-core</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

移除後,用下面的設定即可使用1.1以上的hamcrest

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit-dep</artifactId>
        <version>4.8.2</version>
    </dependency>
    <dependency>
        <groupId>org.hamcrest</groupId>
        <artifactId>hamcrest-library</artifactId>
        <version>1.3</version>
    </dependency>

junit 4.11後已經從程式碼移除對hamcrest的依賴了,可以直接用 <artifactId>junit</artifactId> 而不需用 <artifactId>junit-dep</artifactId>

Matchers

以下列出幾個比較特別的Matcher

  1. describedAs()
  2. either()
  3. both()
  4. emptyIterable()
  5. emptyArray()
  6. eventFrom()
  7. hasEntry()
  8. hasItem()
  9. hasItemInArray()
  10. hasItems()
  11. hasProperty
  12. hasXPath()
  13. hasSize()
  14. hasToString()
  15. isIn()
  16. isOneOf()
  17. nullValue()
  18. samePropertyValuesAs()
  19. typeCompatibleWith()

日期處理?

Hamcrest & Android

Hamcreate(1.3-R.C2)有兩個包裝方式,一個是 all-in-one的jar,一個是lib跟core分開的jars,不論那一種格式,丟到android的開發環境,都會在compile成dalvik版本時發生以下的錯誤:

hamcreat-all.jar的錯誤是JFlexLexer不能被compile成dalvik版的

UNEXPECTED TOP-LEVEL EXCEPTION:
com.android.dx.cf.code.SimException: local variable type mismatch: attempt to set or access a value of type java.lang.Object using a local variable of type int. This is symptomatic of .class transformation tools that ignore local variable information.
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.cf.code.BaseMachine.throwLocalMismatch(BaseMachine.java:550)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.cf.code.Simulator$SimVisitor.visitLocal(Simulator.java:570)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.cf.code.BytecodeArray.parseInstruction(BytecodeArray.java:481)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.cf.code.Simulator.simulate(Simulator.java:99)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.cf.code.Ropper.processBlock(Ropper.java:684)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.cf.code.Ropper.doit(Ropper.java:639)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.cf.code.Ropper.convert(Ropper.java:252)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.dex.cf.CfTranslator.processMethods(CfTranslator.java:252)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.dex.cf.CfTranslator.translate0(CfTranslator.java:131)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.dex.cf.CfTranslator.translate(CfTranslator.java:85)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.command.dexer.Main.processClass(Main.java:369)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.command.dexer.Main.processFileBytes(Main.java:346)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.command.dexer.Main.access$400(Main.java:59)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:294)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:244)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:130)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:108)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.command.dexer.Main.processOne(Main.java:313)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.command.dexer.Main.processAllFiles(Main.java:233)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.dx.command.dexer.Main.run(Main.java:185)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at sun.reflect.GeneratedMethodAccessor13.invoke(Unknown Source)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at java.lang.reflect.Method.invoke(Method.java:597)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.ide.eclipse.adt.internal.build.DexWrapper.run(DexWrapper.java:179)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.ide.eclipse.adt.internal.build.BuildHelper.executeDx(BuildHelper.java:585)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at com.android.ide.eclipse.adt.internal.build.builders.PostCompilerBuilder.build(PostCompilerBuilder.java:490)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:629)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:172)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:203)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at org.eclipse.core.internal.events.BuildManager$1.run(BuildManager.java:255)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:258)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at org.eclipse.core.internal.events.BuildManager.basicBuildLoop(BuildManager.java:311)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:343)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at org.eclipse.core.internal.events.AutoBuildJob.doBuild(AutoBuildJob.java:144)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at org.eclipse.core.internal.events.AutoBuildJob.run(AutoBuildJob.java:242)
[2011-04-12 10:16:57 - Android-libmpg_Test] Dx  at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)
...at bytecode offset 0000001b
locals[0000]: Lorg/hamcrest/generator/qdox/parser/impl/JFlexLexer;
locals[0001]: I
locals[0002]: [C
locals[0003]: [C
locals[0004]: [I
locals[0005]: [I
locals[0006]: <invalid>
locals[0007]: <invalid>
locals[0008]: <invalid>
locals[0009]: <invalid>
locals[000a]: <invalid>
locals[000b]: <invalid>
locals[000c]: <invalid>
locals[000d]: <invalid>
locals[000e]: <invalid>
locals[000f]: <invalid>
locals[0010]: <invalid>
stack[top0]: [B
...while working on block 001b
...while working on method yylex:()I
...while processing yylex ()I
...while processing org/hamcrest/generator/qdox/parser/impl/JFlexLexer.class

而 hamcrest-core-1.3.RC2.jar + hamcrest-library-1.3.RC2.jar 版的則是

The error you get in Android ADK is:-
Error generating final archive: duplicate entry: LICENSE.txt

最簡單的方式就是core + lib這版的中其一個LICENSE.txt刪掉即可,如果jar裡沒有LICENSE.txt的會有版權問題,可以再把兩個jar壓縮成一個jar,保留一個LICENSE.txt即可。 處理完後,不會像官版的hamcreat-all.jar有JFlexLexer錯誤的錯誤,那個JFlexLexer好像是Matcher的包裝工具用到的class,可有可無。

有個功能跟hamcrest很像,但api比較直覺的assertion framework - FEST assert

Resources