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.
Related
I am aware that I can make a TestSuite enumerating all the classes that I want, for example:
#RunWith(Suite.class)
#SuiteClasses({SQLServerTests1.class, SQLServerTest2.class, ... })
public class AllSQLServerTests {}
However I have almost 100+ classes and I don't want to have to remember to include any new one in the #SuiteClasses annotation.
As my classes have a naming convention (starting with "SQLServer" for example) I am searching for a way to do something like this:
#RunWith(Suite.class)
#SuiteClasses(prefix="SQLServer")
public class AllSQLServerTests {}
is it possible with plain JUnit? with spring or any other framework?
Tag'em
You can add many tags to each test or test class:
#Test
#Tag("red")
#Tag("production")
public void testWithColour() {...}
#RunWith(JUnitPlatform.class)
#IncludeTags("red & !production")
public class JUnit5Example {
//...
}
You can also use #ExcludeTags but it cannot co-exist with #IncludeTags
Run all in test package
#RunWith(JUnitPlatform.class)
#SelectPackages("com.acme.megaproduct.slowtests")
public class JUnit5Example {
//...
}
Write custom Test Runner
Perhaps none of the above can acommodate your needs, in which case you can add custom filtering by writing your own runner.
See here for step by step how to do it.
Then you just use it like:
#RunWith(MyCustomRunner.class)
public class CustomTestSuite {
//...
}
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.
I need to know the suite class that included the currently running JUnit test. For example, if you have
#SuiteClasses({SubSuite.class})
class ParentSuite { }
#SuiteClasses({TestCase.class})
class SubSuite { }
class TestCase {
#Test
public void testMethod() { }
}
and execute ParentSuite with JUnit, then I want to get a reference to ParentSuite.class. Is this possible?
There is the TestWatcher rule that gets you an instance of Description, which is kind of in the right direction, but that does not include the suite class.
I know this is probably not the best way to write unit tests. My original problem is to run a validation on all classes that are in the project under test, but not those of the dependencies. The TestCase will be in a dependency and included by test suites in other projects. The only solution I could think of is filter those classes with the same source location as that of the top-most-suite. To make that more clear:
BaseLibrary
* contains TestCase and TestSuite
* has classes that should not be validated
ConsumerProject
* has a test-scoped and test-classified dependency to BaseLibrary
* contains ParentSuite
* has classes that should be validated
You probably want to use JUnit #Category https://github.com/junit-team/junit/wiki/Categories
Here's a blog on how to make Categories https://weblogs.java.net/blog/johnsmart/archive/2010/04/25/grouping-tests-using-junit-categories-0
This way you can make Categories for each of your projects.
public interface ConsumerProject {}
Then you can use the #Category annotation to mark test classes (or even test methods) as being in particular categories:
#Category(ConsumerProject.class)
public class TestCase { ... }
Then your suites can be set up to run all the tests for particular categories
#RunWith(Categories.class)
#IncludeCategory(ConsumerProject.class)
#SuiteClasses( { ....})
public class ConsumerProjectSuite { }
You can even have the same test get marked with multiple categories
#Category({ConsumerProject.class, OtherProject.class})
public class CommonTests { }
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.
Is there any way to group tests in JUnit, so that I can run only some groups?
Or is it possible to annotate some tests and then globally disable them?
I'm using JUnit 4, I can't use TestNG.
edit: #RunWith and #SuiteClasses works great. But is it possible to annotate like this only some tests in test class? Or do I have to annotate whole test class?
JUnit 4.8 supports grouping:
public interface SlowTests {}
public interface IntegrationTests extends SlowTests {}
public interface PerformanceTests extends SlowTests {}
And then...
public class AccountTest {
#Test
#Category(IntegrationTests.class)
public void thisTestWillTakeSomeTime() {
...
}
#Test
#Category(IntegrationTests.class)
public void thisTestWillTakeEvenLonger() {
...
}
#Test
public void thisOneIsRealFast() {
...
}
}
And lastly,
#RunWith(Categories.class)
#ExcludeCategory(SlowTests.class)
#SuiteClasses( { AccountTest.class, ClientTest.class })
public class UnitTestSuite {}
Taken from here: https://community.oracle.com/blogs/johnsmart/2010/04/25/grouping-tests-using-junit-categories-0
Also, Arquillian itself supports grouping:
https://github.com/weld/core/blob/master/tests-arquillian/src/test/java/org/jboss/weld/tests/Categories.java
Do you want to group tests inside a test class or do you want to group test classes? I am going to assume the latter.
It depends on how you are running your tests. If you run them by Maven, it is possible to specify exactly what tests you want to include. See the Maven surefire documentation for this.
More generally, though, what I do is that I have a tree of test suites. A test suite in JUnit 4 looks something like:
#RunWith(Suite.class)
#SuiteClasses({SomeUnitTest1.class, SomeUnitTest2.class})
public class UnitTestsSuite {
}
So, maybe I have a FunctionTestsSuite and a UnitTestsSuite, and then an AllTestsSuite which includes the other two. If you run them in Eclipse you get a very nice hierarchical view.
The problem with this approach is that it's kind of tedious if you want to slice tests in more than one different way. But it's still possible (you can for example have one set of suites that slice based on module, then another slicing on the type of test).
To handle the globally disabling them, JUnit (4.5+) has two ways One is to use the new method assumeThat. If you put that in the #BeforeClass (or the #Before) of a test class, and if the condition fails, it will ignore the test. In the condition you can put a system property or something else that can be globally set on or off.
The other alternative is to create a custom runner which understands the global property and delegates to the appropriate runner. This approach is a lot more brittle (since the JUnit4 internal runners are unstable and can be changed from release to release), but it has the advantage of being able to be inherited down a class hierarchy and be overridden in a subclass. It is also the only realistic way to do this if you have to support legacy JUnit38 classes.
Here is some code to do the custom Runner. Regarding what getAppropriateRunnerForClass might do, the way I implemented it was to have a separate annotation that tells the custom runner what to run with. The only alternative was some very brittle copy paste from the JUnit code.
private class CustomRunner implements Runner
private Runner runner;
public CustomRunner(Class<?> klass, RunnerBuilder builder) throws Throwable {
if (!isRunCustomTests()) {
runner = new IgnoredClassRunner(klass);
} else {
runner = getAppropriateRunnerForClass(klass, builder);
}
public Description getDescription() {
return runner.getDescription();
}
public void run(RunNotifier notifier) {
runner.run(notifier);
}
}
EDIT: The #RunWith tag only works for a whole class. One way to work around that limiation is to move the test methods into a static inner class and annotate that. That way you have the advantage of the annotation with the organization of the class. But, doing that won't help with any #Before or #BeforeClass tags, you will have to recreate those in the inner class. It can call the outer class's method, but it would have to have its own method as a hook.
In JUnit 5 you can declare #Tag for filtering tests, either at the class or method level; analogous to test groups in TestNG or Categories in JUnit 4
From the javadoc :
tags are used to filter which tests are executed for a given test
plan. For example, a development team may tag tests with values such
as "fast", "slow", "ci-server", etc. and then supply a list of tags to
be used for the current test plan, potentially dependent on the
current environment.
For example you could declare a test class with a "slow" #Tag that will be inherited for all methods and override it for some methods if required :
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
#Tag("slow")
public class FooTest{
//
#Test
void loadManyThings(){
...
}
#Test
void loadManyManyThings(){
...
}
#Test
#Tag("fast")
void loadFewThings(){
...
}
}
You could apply the same logic for other test classes.
In this way test classes (and methods too) belongs to a specific tag.
As a good practice instead of copying and pasting #Tag("fast") and #Tag("slow") throughout the test classes, you can create custom composed annotations.
For example :
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.jupiter.api.Tag;
#Target({ ElementType.TYPE, ElementType.METHOD })
#Retention(RetentionPolicy.RUNTIME)
#Tag("slow")
public #interface Slow {
}
and use it as :
#Test
#Slow
void slowProcessing(){
...
}
To enable or disable test marked with a specific tag during the text execution you can rely on the maven-surefire-plugin documentation :
To include tags or tag expressions, use groups.
To exclude tags or tag expressions, use either excludedGroups.
Just configure in your pom.xml the plugin according to your requirement (example of the doc) :
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<groups>acceptance | !feature-a</groups>
<excludedGroups>integration, regression</excludedGroups>
</configuration>
</plugin>
</plugins>
</build>
For information the test goal documentation is not updated.
Try JUnit Test Groups. From documentation :
#TestGroup("integration")
public class MyIntegrationTest {
#ClassRule
public static TestGroupRule rule = new TestGroupRule();
...
}
Execute a simple test group: -Dtestgroup=integration
Execute multiple test groups: -Dtestgroup=group1,group2
Execute all test groups: -Dtestgroup=all
You can create test Suite objects that contain groups of tests. Alternatively, your IDE (like Eclipse) may have support for running all the tests contained in a given package.
You can Use Test Suite(http://qaautomated.blogspot.in/2016/09/junit-test-suits-and-test-execution.html) or you can Junit Categories(http://qaautomated.blogspot.in/2016/09/junit-categories.html) for grouping your test cases effectively.