I have an application I want to test:
import foo.ExtClass;
public class App {
public static void main(String[] args) {
ExtClass ext = new ExtClass();
...
}
}
I want to write a unit test for this application, however I do not want to use the foo.ExtClass, but use another mock implementation for the class.
Normally I would use a factory to instantiate the class according to some configuration that can be controlled in the unit test.
However, in this case, I cannot modify the tested app.
I was thinking in the direction of writing a custom class loader to load the mock class instead of the real class - not sure if this is possible without any modification to the tested app, and how.
As an option you can use custom classloader, which will substite your class with a testing one. So basically instead of loading ExtClass from your app package, your classloader will load the same class from your testing package with the mock implementation.
Here is an example:
How to replace classes in a running application in java ?
Also there is very usefull tutorial: https://zeroturnaround.com/rebellabs/reloading-objects-classes-classloaders/
The approach I finally used:
Created a separate project with my mock implementation of foo.ExtClass,
and the unit tests.
This way the mock implementation appeared in the classpath before the real implementation, and the original (tested) project remained untouched.
Related
I am working with grails application. I want to perform methods like get(),save(),delete(),findBy() etc and associated with domains of grails application. When I execute Domain.get() method inside Utils or src/groovy package I get following error.
Caught: java.lang.IllegalStateException: Method on class [Domain Class] was used outside of a Grails application. If running in the context of a test using the mocking API or bootstrap Grails correctly.
java.lang.IllegalStateException: Method on class [Domain Class] was used outside of a Grails application. If running in the context of a test using the mocking API or bootstrap Grails correctly.
Any one help me how can I use domain class method inside Utils or src/groovy classes?
This error is caused by interacting with GORM entities that have not been properly registered with GORM. The error doesn't have anything to do with where the interaction is initiated from (src/groovy, grails-app/services/, etc...).
Not always, but most often this error occurs in a testing environment where the entity type has not been registered with GORM.
See the project at https://github.com/jeffbrown/illegalaccessgorm. That project contains the following.
A domain class:
// grails-app/domain/demo/Person.groovy
package demo
class Person {
String name
}
A service:
// grails-app/services/demo/HelperService.groovy
package demo
class HelperService {
int getNumberOfPeople() {
Person.count()
}
}
A utility class:
// src/groovy/demo/SomeHelper.groovy
package demo
class SomeHelper {
int getNumberOfPeople() {
Person.count()
}
}
A unit test for the service:
// test/unit/demo/HelperServiceSpec.grovy
package demo
import grails.test.mixin.TestFor
import spock.lang.Specification
#TestFor(HelperService)
#Mock(Person)
class HelperServiceSpec extends Specification {
void "test gorm method"() {
expect:
service.numberOfPeople == 0
}
}
A unit test for the utility class:
// test/unit/demo/SomeHelperSpec.groovy
package demo
import spock.lang.Specification
#Mock(Person)
class SomeHelperSpec extends Specification {
void "test gorm method"() {
given:
def helper = new SomeHelper()
expect:
helper.numberOfPeople == 0
}
}
Both of those tests pass. If you remove the #Mock(Person) from either of them, the test will fail with the following:
java.lang.IllegalStateException: Method on class [demo.Person] was used outside of a Grails application. If running in the context of a test using the mocking API or bootstrap Grails correctly.
If the problem is happening in some context other than a test, knowing more about the context would be helpful. Other likely suspects are Java entities that are not being initialized properly for some reason and in some cases domain classes brought in from plugins can be problematic.
Also, knowing what version of Grails you are using may be relevant.
I hope that all makes sense.
You shouldn't use domain classes inside src/groovy or inside utils. You should use services for it. Check out best practises for Grails architecture:
Domain
Favor placing model domain specific logic in its own domain. Anything that applies to a single domain with few dependencies should go in its domain class. But keep it restricted to the logic specific to that domain only - more complex business logic that deals with a group of domains belongs to a service.
To reuse common partial queries or decompose the complex logic, use named queries and chain them together as required, just like one commonly chains jQuery function calls.
Don't mix any other common utility classes or value objects in the domain folder, rather they can go in src/groovy. If these classes need to support validation, one can annotate them with #Validateable.
If you still want to do it, check this FAQ:
import org.codehaus.groovy.grails.commons.ApplicationHolder
//…
def book = ApplicationHolder.application.getClassForName("library.Book").findByTitle("Groovy in Action")
I know a way to print the classpath of a project at runtime like here:
http://www.mkyong.com/java/how-to-print-out-the-current-project-classpath/
But sometimes the main is even too late, for example when using spring.
Is there a way to print something(e.g. classpath) even before Spring starts the injection process?
Providing some context, i am running a unit test in spring as follows:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:/jmsAppContext.xml")
public class TestProjectProvisioningIntegration
{
....
}
It finds correctly the jmsAppContext.xml, but fails to find one of the properties files.
To get the same effect as you have in the link you posted, you could get the classpath in a static initializer (just do the same as the example, only then in a static { ... } block instead of a main method. The JVM will execute the static initializer first, before loading any other classes your class depends on (other than the classes you reference in the static initializer).
I've got a utility class that I've created:
package com.g2.quizification.utils;
import com.g2.quizification.domain.Question;
public class ParsingUtils {
public static Question parse(String raw) {
Question question = new Question();
//TODO: parse some stuff
return question;
}
}
...that lives here:
I've also followed the tutorials and created a testing app, that looks like this:
And here's my test code, just waiting for some good 'ole TDD:
package com.g2.quizification.utils.test;
import com.g2.quizification.domain.Question;
import com.g2.quizification.utils.ParsingUtils;
public class ParsingUtilsTest {
public void testParse() {
String raw = "Q:Question? A:Answer.";
Question question = ParsingUtils.parse(raw);
//assertEquals("Question?", question.getQuestion());
//assertEquals("Answer.", question.getAnswer());
}
}
The test class is obviously missing the extension, but all the examples seem to only show extending something like ActivityUnitTestCase. I'm not testing an activity; I just want to test a static method in a utility class. Is that possible?
It seems like creating a utility test class should be simple, but I'm not sure what the next step is and/or what I'm missing.
The best approach for test project is to add the test project so that its root directory tests/ is at the same level as the src/ directory of the main application's project. If you are using junit4 and eclipse, you can just right-click on the util class you want to test and choose New -> JUnit Test Case.
Basically I would expect a new test class named ParsingUtilTest under the source folder tests/ and within the package com.g2.quizification.utils.test. The test class should extend TestCase and each method you want to test in that util class should have a new method in the test class with the name preceded with "test". I mean to say, suppose you have a method name in ParsingUtils called parseXml. The test method name in ParsingUtilsTest (which Extend 'TestCase') should be named testParseXml
The test class is obviously missing the extension, but all the examples seem to only show extending something like ActivityUnitTestCase. I'm not testing an activity; I just want to test a static method in a utility class. Is that possible?
Yes, as long as the class your are testing has nothing to do with android apis. And if you do need to test code with android api dependencies, for example, testing a view or an activity, you might want to have a try with robolectric. It's faster than the ones that extend ActivityUnitTestCase.
I have been playing with robolectric a lot (to do TDD on android), and so far, I prefer version 1.1 or 1.2 to 2.x, more stable and run fast.
Besides the tools mentioned above, there are many practices for writing good test cases, naming conventions, code refactoring and such.
It seems like creating a utility test class should be simple, but I'm not sure what the next step is and/or what I'm missing.
Its good to begin with small steps, xUnit Test Patterns: Refactoring Test Code and Extreme Programming Explained are some good books for your reference.
Hi I need to write Junit tests for an Android project but it has JNI methods as it uses webkit.Is there any way I can test those android methods(I dont want to test JNI methods).
Its like:
public void androidMethod(){
//some android code
nativeInit(); //how do I mock such methods?
//some code again
}
I have tried powermock,easymock,roboelectric but wasnt successful.Please help me.
I yesterday found I could solve this with Mockito (I didn't try powermock or easymock). Assuming your class is class C, my solution is:
C c=spy(new C);
doNothing().when(c).nativeInit();
c.androidMethod()
verify(c).nativeInit();
This does, of course, require that nativeInit is visible to the test.
Similar Problem
I had the same problem event though I was already using mockito in JUnit tests under src/test. Once I added tests under src/androidTest I started having issues, including this crash:
Mockito cannot mock/spy because :
- final class
And after making the class open, manually, I still got crashes in the JNI layer as it tried to load the *.so library (which wouldn't happen if mocks were working properly).
Working Solution
Instead, what I had to do was open the class for testing purposes using Kotlin's all-open plugin. The process is also explained well in this recent medium post but it boils down to the following four simple changes that are also modeled in one of the architecture components sample apps:
1. Make these additions to build.gradle:
buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-allopen:${versions.kotlin}"
}
}
apply plugin: "kotlin-allopen"
allOpen {
// marker for classes that we want to be able to extend in debug builds
annotation 'com.your.package.name.OpenClass'
}
2. Add the corresponding annotations in the debug flavor. For example: app/src/debug/java/com/your/package/name/OpenForTesting.kt
package com.your.package.name
#Target(AnnotationTarget.ANNOTATION_CLASS)
annotation class OpenClass
#OpenClass
#Target(AnnotationTarget.CLASS)
annotation class OpenForTesting
3. Add the corresponding annotation in the release flavor. For example: app/src/release/java/com/your/package/name/OpenForTesting.kt
package com.your.package.name
#Target(AnnotationTarget.CLASS)
annotation class OpenForTesting
4. Add the #OpenForTesting annotation to the class that needs to be mocked
package com.your.package.name
#OpenForTesting
class JniClassOfVictory {
...
external fun nativeInit()
...
companion object {
init {
System.loadLibrary("victoryeveryday")
}
}
}
The result is a flexible way to mark classes as open without actually making them open in release builds. Of course, this is because the #OpenForTesting annotation that we created in release is not marked with #OpenClass but the same annotation in debug is marked with #OpenClass. In build.gradle we designated that annotation as the signal to the kotlin-allopen plugin. So any class annotated with #OpenForTesting will be made open at compile-time but only on Debug builds.
How to unit test private (means with package visibility) classed in java?
I have a package, only one class is public in this package, other classes are private. How to cover other classed with unit tests? I would like to include unit tests in resting jar.
Create the unit test class in the same package.
For example, If com.example.MyPrivateClass located in src/main/java/com/example/MyPrivateClass.java
Then the test class will be in same package com.example.MyPrivateClassTestCase and will be located in src/test/java/com/example/MyPrivateClassTestCase.java
There are two ways to do this.
The standard way is to define your test class in the same package of the class to be tested. This should be easily done as modern IDE generates test case in the same package of the class being tested by default.
The non-standard but very useful way is to use reflection. This allows you to define private methods as real "private" rather than "package private". For example, if you have class.
class MyClass {
private Boolean methodToBeTested(String argument) {
........
}
}
You can have your test method like this:
class MyTestClass {
#Test
public void testMethod() {
Method method = MyClass.class.getDeclaredMethod("methodToBeTested", String.class);
method.setAccessible(true);
Boolean result = (Boolean)method.invoke(new MyClass(), "test parameter");
Assert.assertTrue(result);
}
}
As indicated in #Kowser's answer, the test can be in the same package.
In Eclipse, and I assume other IDEs, one can have classes in different projects but in the same package. A project can be declared to depend on another project, making the other project's classes available. That permits a separate unit test project that depends on the production project and follows its package structure, but has its own root directory.
That structure keeps the test code cleanly separated from production code.