Posted March 13, 201510 yr Hi, I'm trying to write a unit test that access Items and Blocks. Now, Items and Blocks lists are null during such tests.... Like: println(Items.leather) This prints null. Is there a way to initialize correctly the items and blocks in a test scope, i.e., without having the game running? thank you! []s, just you wait!
March 13, 201510 yr Because those items are defined at runtime. Look at Item.java Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable. If you think this is the case, JUST REPORT ME. Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice. Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked. DO NOT PM ME WITH PROBLEMS. No help will be given.
March 13, 201510 yr Author I see. So I figured I could call Item.registerItems() but this fails with: sun.misc.Launcher$AppClassLoader cannot be cast to net.minecraft.launchwrapper.LaunchClassLoader java.lang.ClassCastException: sun.misc.Launcher$AppClassLoader cannot be cast to net.minecraft.launchwrapper.LaunchClassLoader at cpw.mods.fml.common.ModClassLoader.<init>(ModClassLoader.java:46) at cpw.mods.fml.common.Loader.<init>(Loader.java:181) just you wait!
March 13, 201510 yr Unit testing Minecraft is a pain you have to run through the full startup because we do a lot of black magic. It's better to just unit test your own code apart from the MC code. I do Forge for free, however the servers to run it arn't free, so anything is appreciated. Consider supporting the team on Patreon
March 13, 201510 yr Author I would be ok with a full startup if that is what is required. I'm developing a lib for modders, so it is quite hard to be totally isolated here. From the error, I got that using the LaunchClassLoader is necessary. I tried a custom junit runner which included the code bellow. The code is scala but is very straightforward to read. val classLoader = new LaunchClassLoader(Thread.currentThread.getContextClassLoader.asInstanceOf[urlClassLoader].getURLs) Thread.currentThread.setContextClassLoader(classLoader) But then this ended up destroying the specs2 context. The error is: java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.intellij.junit4.IdeaSuite.getDescription(IdeaSuite.java:55) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:43) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) Caused by: java.lang.ClassCastException: com.easyforger.recipes.RecipesSpec cannot be cast to org.specs2.specification.core.SpecificationStructure which feels like classloaders being mixed up. Does what I tried make sense? Or perhaps there is a better way to trigger the full startup and lets things be available for usage? just you wait!
March 13, 201510 yr Hi I've run into this problem myself and after wasting hours trying to set up stubs for vanilla objects, the way I solved it was to add a "Tester" item ingame. When the player uses the item, it interrupts the game and executes all the unit tests and integration tests using the already-set-up vanilla objects. Not as friendly as separate junit tests but it did the trick. -TGG
March 14, 201510 yr Author Hi I've run into this problem myself and after wasting hours trying to set up stubs for vanilla objects, the way I solved it was to add a "Tester" item ingame. When the player uses the item, it interrupts the game and executes all the unit tests and integration tests using the already-set-up vanilla objects. Not as friendly as separate junit tests but it did the trick. -TGG Now this is something I haven't considered. Other than being triggered from inside the game, the tests ended up being just plain old junit tests? Even if it is not a clean way to write tests, it certainly sounds like a whole lot more fun then fighting classloaders or stubbing whole universes =) just you wait!
March 14, 201510 yr Hi I've run into this problem myself and after wasting hours trying to set up stubs for vanilla objects, the way I solved it was to add a "Tester" item ingame. When the player uses the item, it interrupts the game and executes all the unit tests and integration tests using the already-set-up vanilla objects. Not as friendly as separate junit tests but it did the trick. -TGG Now this is something I haven't considered. Other than being triggered from inside the game, the tests ended up being just plain old junit tests? Even if it is not a clean way to write tests, it certainly sounds like a whole lot more fun then fighting classloaders or stubbing whole universes =) I guess it would be more accurate to call them "junit-style" tests because I didn't actually write them using the usual junit annotations, and the testing code is in the main src not in testing packages (The Tester Item is enabled using a command line parameter). But yes, that's the idea. It worked really well for the mod I was making which had to copy blocks back and forth - I created a testing world, used the "Testing Item" to initialise a test region, perform a series of test copy & rotate operations, and check the results against the expected outcome at each step. Logging of any errors. I must have discovered twenty or thirty subtle bugs that way. If you know a lot more about junit than me, you could probably figure out how to do it more cleanly by calling the right junit methods to set up the logging, start the testing, etc. Might not be worth it. You just have to be careful to remember which side your test code needs to run on, but that's not hard. You wouldn't need an item either, just a command line parameter or similar should be enough - for example you have a tick handler which checks for the presence of the parameter and runs tests if required. -TGG
March 14, 201510 yr Author Thank you TGG ! I managed to kick-start my tests from a preInit - which is enough for now. I might change for a item or something if I end up needing a running world at some point. I'm not using junit as well, but specs2 instead, a scala testing framework. I still have to figure out a good way to call specs2 (its a bit ugly right now) - but I already know it is possible and solve the previous issues. My plan to lower issue with the tests in the src/main folder is to have all tests in a separated mod, so that they don't have to be bundled with the library itself. So the idea would be that the test mod depends on the library, and all I have to do is to add the mod to a mods folder of any minecraft installation and it should work. Makes sense? []s, just you wait!
March 14, 201510 yr Makes sense to me And from what I've seen, it would make you the second person in the history of modding to use automated testing on their mod I can tell you from painful experience of two version upgrades that regression testing in particular is very very important. -TGG
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.