Mengatasi Kegagalan Menjalankan test-app Dari Luar Direktori Proyek


I was surprised to find out that Griffon author has a link to my blog in one of his tweet. That was awesome. I hope my blog could be useful even it is not written in English.

Pada saat memberikan perintah command line griffon, maka secara otomatis lokasi direktori saat itu dianggap sebagai lokasi proyek yang sedang aktif.   Namun, ada kalanya saya harus mengerjakan perintah command line griffon dari luar direktori proyek.  Sebagai contoh, bila saya ingin mengerjakan perintah griffon tersebut di cron atau dipanggil dari script lain.  Bila sudah demikian, maka lokasi direktori yang sedang aktif belum tentu adalah lokasi direktori yang berisi kode program proyek Griffon.

Beruntungnya, saya bisa memberikan parameter base.dir untuk memberitahu lokasi proyek.  Dengan demikian, perintah command line griffon dapat dipanggil dari direktori mana saja.  Sebagai contoh, di Gant (ini adalah sesuatu yang mirip seperti Ant tetapi memakai bahasa Groovy bukan XML), saya bisa memberikan definisi seperti berikut ini:

target('install': 'Melakukan instalasi plugin secara otomatis') {
   execute.shell "griffon -Dbase.dir=C:\\projects\latihan install-plugin"
}

Saya boleh mengerjakan Gant script di atas dari folder mana saja karena saya menentukan lokasi proyek melalui base.dir.

Untuk contoh yang lebih realistis, saya ingin Gant melakukan pengujian proyek (perintah test-app) dan saya akan memanggilnya dari luar lokasi proyek karena Gant script ini akan menguji lebih dari satu proyek Griffon secara otomatis.  Saya dapat memberikan definisi yang terlihat seperti berikut ini:

target('test': 'Melakukan pengujian aplikasi') {
   execute.shell "griffon -Dbase.dir=C:\\projects\latihan test-app"
}

Seharusnya script di atas dapat berjalan dengan lancar.  Tapi pada Griffon 1.2.0, saya malah menemukan pesan kesalahan seperti berikut ini:

java.lang.IllegalArgumentException: Could not load class in test type 'unit'
	at org.codehaus.griffon.cli.GriffonScriptRunner.executeWithGantInstance(GriffonScriptRunner.java:648)
	at org.codehaus.griffon.cli.GriffonScriptRunner.executeWithGantInstanceNoException(GriffonScriptRunner.java:667)
	at org.codehaus.griffon.cli.GriffonScriptRunner.callPluginOrGriffonScript(GriffonScriptRunner.java:392)
	at org.codehaus.griffon.cli.GriffonScriptRunner.doExecuteCommand(GriffonScriptRunner.java:303)
	at org.codehaus.griffon.cli.GriffonScriptRunner.main(GriffonScriptRunner.java:141)
	at org.codehaus.griffon.cli.support.GriffonStarter.rootLoader(GriffonStarter.java:198)
	at org.codehaus.griffon.cli.support.GriffonStarter.main(GriffonStarter.java:223)
Caused by: java.lang.IllegalArgumentException: Could not load class in test type 'unit'
	at org.codehaus.griffon.test.support.GriffonTestTypeSupport.loadClass(GriffonTestTypeSupport.groovy:249)
	at org.codehaus.griffon.test.support.GriffonTestTypeSupport.sourceFileToClass(GriffonTestTypeSupport.groovy:229)
	at org.codehaus.griffon.test.junit4.JUnit4GriffonTestType$_getTestClasses_closure1.doCall(JUnit4GriffonTestType.groovy:67)
	at org.codehaus.griffon.test.support.GriffonTestTypeSupport$_eachSourceFile_closure3_closure8.doCall(GriffonTestTypeSupport.groovy:197)
	at org.codehaus.griffon.test.support.GriffonTestTypeSupport$_eachSourceFile_closure3.doCall(GriffonTestTypeSupport.groovy:196)
	at org.codehaus.griffon.test.support.GriffonTestTypeSupport.eachSourceFile(GriffonTestTypeSupport.groovy:195)
	at org.codehaus.griffon.test.junit4.JUnit4GriffonTestType.getTestClasses(JUnit4GriffonTestType.groovy:66)
	at org.codehaus.griffon.test.junit4.JUnit4GriffonTestType.doPrepare(JUnit4GriffonTestType.groovy:55)
	at org.codehaus.griffon.test.support.GriffonTestTypeSupport.prepare(GriffonTestTypeSupport.groovy:95)
	at org.codehaus.griffon.test.GriffonTestType$prepare.call(Unknown Source)
	at _GriffonTest$_run_closure5.doCall(_GriffonTest.groovy:294)
	at _GriffonTest$_run_closure5.call(_GriffonTest.groovy)
	at _GriffonTest$_run_closure3.doCall(_GriffonTest.groovy:255)
	at _GriffonTest$_run_closure2_closure25.doCall(_GriffonTest.groovy:215)
	at _GriffonTest$_run_closure2.doCall(_GriffonTest.groovy:202)
	at _GriffonSettings$_run_closure1.doCall(_GriffonSettings:80)
	... 7 more
Caused by: java.lang.ClassNotFoundException: SimpleJpaHandlerUnitTest
	at java_lang_ClassLoader$loadClass.call(Unknown Source)
	at org.codehaus.griffon.test.support.GriffonTestTypeSupport.loadClass(GriffonTestTypeSupport.groovy:247)
	... 22 more

Bagian yang paling menarik disini terlihat bahwa kesalahannya adalah ClassNotFoundException dimana Griffon tidak bisa menemukan class yang akan diuji.

Mengapa bisa demikian?  Untuk itu, saya akan membuka file GriffonTestTypeSupport.groovy baris 247 yang isinya seperti berikut ini:

protected Class loadClass(String className) {
  try {
    getTestClassLoader().loadClass(className)
  } catch (ClassNotFoundException e) {
    throw new IllegalArgumentException("Could not load class in test type '$name'", e)
  }
}

Karena hanya ada 1 baris perintah, maka saya yakin kesalahannya ada di method getTestClassLoader() yang isinya seperti berikut ini:

protected ClassLoader getTestClassLoader() {
  if (!testClassLoader) {
    def classPathAdditions = [getSourceDir()]
    if (compiledClassesDir) classPathAdditions << compiledClassDir
    testClassLoader = new URLClassLoader(classPathAdditions*.toURI()*.toURL() as URL[], buildBinding.classLoader)
  }
  testClassLoader
}

Saya akan mulai dengan menelusuri method getSourceDir(). Berikut ini yang saya temukan:

protected File getSourceDir() {
  if (!sourceDir) {
    sourceDir = new File("test/$relativeSourcePath") // TODO: remove this hardcoding of 'test/'
  }
  sourceDir
}

Seperti yang diberikan dalam komentar, nilai sourceDir bersifat relative terhadap lokasi folder saat ini!  Ini artinya, sia-sia memakai base.dir.  Saya harus mengubah method ini agar ini memakai nilai base.dir seperti yang terlihat berikut ini:

protected File getSourceDir() {
  if (!sourceDir) {
    sourceDir = new File("$BuildSettingsHolder.settings.baseDir/test/$relativeSourcePath") // TODO: remove this hardcoding of 'test/'
  }
  sourceDir
}

Setelah men-build ulang Griffon, Gant yang memanggil test-app dari folder lain (memakai base.dir) akhirnya dapat bekerja sesuai dengan harapan.

Perihal Solid Snake
I'm nothing...

One Response to Mengatasi Kegagalan Menjalankan test-app Dari Luar Direktori Proyek

  1. Thanks for the thorough explanation and posting a fix. I’ve filed http://jira.codehaus.org/browse/GRIFFON-620 to correct the problem.

    Cheers,
    Andres

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: