everybody, I am a beginner in Spring and I am encountering some problems with #DeclareParents. I follow the instructions in Spring In Action but I fail to realize the introduction.
Here are my codes.
I first define Interface performance
public interface Performance {
void perform();
}
and then implement the interface.
#Component
public class OnePerformance implements Performance {
#Autowired
public OnePerformance(){
}
public void perform() {
System.out.println("The Band is performing....");
}
}
I want to introduce method void performEncore() into Performance.
So I define the Interface,
public interface Encoreable {
void performEncore();
}
implement it,
#Aspect
public class DefaultEncoreable implements Encoreable{
public void performEncore() {
System.out.println("performEncore");
}
}
and introduce it,
#Aspect
#Component
public class EncoreableIntroduction {
#DeclareParents(value="Performance+",
, defaultImpl=DefaultEncoreable.class)
public static Encoreable encoreable;
}
I use autoconfiguration,
#Configuration
#EnableAspectJAutoProxy
#ComponentScan
public class ConcertConfig {
}
However, when testing, I fail to introduce method void performEncore().
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes= ConcertConfig.class)
public class OnePerformanceTest {
#Autowired
private Performance performance;
#Test
public void perform() throws Exception {
performance.perform();
}}
And I also enabled AspectJ Support Plugins.
I have read the book and several blogs carefully but I still can not find the cause. So what may be the cause of this problem? Thanks in advance.
Thanks for M. Deinum, NewUser and Wim Deblauwe. With their help, I finally figured out the problem. The previous JUnit4 class is not correct.
The proper solution to solve this problem is to cast Performance into Encoreable, and then call the performEncore() method.
The code is as follow:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes= ConcertConfig.class)
public class OnePerformanceTest {
#Autowired
private Performance performance;
#Test
public void perform() throws Exception {
Encoreable encoreable = (Encoreable)(performance);
encoreable.performEncore();
}
}
I have an interface that defines a contract (i.e. a Repository), with few implementations. Each method in the interface represents a feature, and I would like to test each feature in its suite test class.
Let's assume a UserRepository interface as follows:
public interface UserRepository {
Set<User> search(String query);
Set<User> findBySomethingSpecific(String criteria1, Integer criteria2);
}
At the moment, to ensure I run the same test cases, I create an abstract test class, and each of my implementations have a test class that extends the abstract test class.
public abstract UserRepositoryTest {
private UserRepository userRepository;
#Before
public void setUp() {
userRepository = createUserRepository();
}
#Test public void aTestForSearch() { ... }
#Test public void anotherTestForSearch() { ... }
#Test public void aTestForSomethingSpecific() { ... }
#Test public void anotherTestForSomethingSpecific() { ... }
protected abstract UserRepository createUserRepository();
}
//------------------------
public class UserRepositoryImplementationTest extends UserRepositoryTest {
#Override
protected UserRepository createUserRepository() {
return new UserRepositoryImplementation();
}
}
I would like to find a way to divide this abstract test class into a set of small tests, because the test class becomes rapidly overwhelmed. I've looked at test suites, but I don't understand how can I create a Suite test class by injecting my different implementations.
As a side not, I've found this question, but some of my repositories require some logic at its creation (for instance, ConnectionPool for a SQL implementation). I currently use the anti-pattern ServiceLocator with different Context classes to handle the creation, but this is static. That's why I had an approach of a test class by implementation, so I can create the context and inject it afterward.
Whit Junit 4 you can create a suite like this:
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
#RunWith(Suite.class)
#Suite.SuiteClasses({
TestFeatureLogin.class,
TestFeatureLogout.class,
TestFeatureNavigate.class,
TestFeatureUpdate.class
})
/**
*
* This suite will execute TestFeatureLogin,TestFeatureLogout,TestFeatureNavigate and TestFeatureUpdate one after the over.
*
* #Before, #After and #Test are no possible of executing in this class.
* #BeforeClas and #AfterClass are allowed only.
*
* */
public class FeatureTestSuite {
// the class remains empty of test,although it is possible set up a before class and after class annotations.
// used only as a holder for the above annotations
#BeforeClass
static public void beforeClass(){
System.out.println(FeatureTestSuite.class.toString() + " BeforeClass Method");
}
#AfterClass
static public void AfterClass(){
System.out.println(FeatureTestSuite.class.toString() + " AfterClass Method");
}
}
The complete example could be found here
Another thing you have to have into account is that #Test is no a good practice of unit testing inside Abstract class. If you want to test your implementations create test classes that extend of Abstract class.
I have following architecture of unit test:
#RunWith(Enclosed.class)
public class ProductTest {
#RunWith(MockitoJUnitRunner.class)
public static abstract class Base {...}
public static class Test1 extends Base{
#Test
public void foo(){...}
}
}
public static class Test2 extends Base{
#Test
public void bar(){...}
}
}
}
If I run unit tests I see following error message:
org.mockito.exceptions.base.MockitoException:
No tests found in Base
Haven't you forgot #Test annotation?
Mockito tries to say me that Base is test bit have noone method annoted with #Test
I have found decision - ignore base class.
Bit it looks like hack. Is there more elegant way?
Move Base outside the ProductTest class (can be in same file) and move RunWith to concrete classes.
Is it possible to parameterize a TestSuite in junit 4 ?
For declaring a class as a test suite I need the annotation #RunWith(Suite.class), but the same annotation is also needed to declare the test as parameterized: #RunWith(Parameterized.class) so I cannot add both to the same class.
I found a similar question in this site that did not help much. So far, all the examples I have found explain how to parameterize simple unit tests, not a complete test tuite.
I believe the basic answer is No, because as you said, the #RunsWith only take one parameter. I found a blog posting that got a bit creative in how to handle this situation.
We don't use the parameterized tests, but may you could create a separate suite like we do that only lists the test classes and the parameterized test could be part of that. I modified our test suite to include a parameterized test class to part of the suite and it ran fine. We create our suite like below where PrimeNumberCheckerTest was a simple I pulled from the web.
package com.jda.portfolio.api.rest.server;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
#RunWith(Suite.class)
#SuiteClasses({ com.mycompany.api.rest.server.resource.TestCartResourceJava.class,
com.mycompany.api.rest.server.resource.TestCustomerResource.class,
com.mycompany.api.rest.server.resource.TestWizardProfileResource.class,
com.mycompany.api.rest.server.interceptor.TestBaseSearchInterceptor.class,
com.mycompany.api.rest.server.resource.TestQueryParameters.class,
com.mycompany.api.rest.server.expression.TestCartExpressionGenerator.class,
com.mycompany.api.rest.server.expression.TestPreferenceExpressionGenerator.class,
com.mycompany.api.rest.server.PrimeNumberCheckerTest.class,
})
public class AllTests {}
Here's the source for the parameterized test case;
package com.jda.portfolio.api.rest.server:
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Suite.SuiteClasses;
#RunWith(Parameterized.class)
#SuiteClasses({PrimeNumberCheckerTest.class})
public class PrimeNumberCheckerTest {
private Integer inputNumber;
private Boolean expectedResult;
private PrimeNumberChecker primeNumberChecker;
#Before
public void initialize() {
primeNumberChecker = new PrimeNumberChecker();
}
// Each parameter should be placed as an argument here
// Every time runner triggers, it will pass the arguments
// from parameters we defined in primeNumbers() method
public PrimeNumberCheckerTest(Integer inputNumber,
Boolean expectedResult) {
this.inputNumber = inputNumber;
this.expectedResult = expectedResult;
}
#Parameterized.Parameters
public static Collection primeNumbers() {
return Arrays.asList(new Object[][] {
{ 2, true },
{ 6, false },
{ 19, true },
{ 22, false },
{ 23, true }
});
}
// This test will run five times since we have as many parameters defined
#Test
public void testPrimeNumberChecker() {
System.out.println("Parameterized Number is : " + inputNumber);
assertEquals(expectedResult,
primeNumberChecker.validate(inputNumber));
}
I was able to parameterize a test suite and use its data in a test class member of the suite as follows:
In JUTsuite:
#RunWith(Suite.class)
#Suite.SuiteClasses({
JUT_test1.class,
})
public class JUTSuite{
// Declare all variables/objects you want to share with the test classes, e.g.
protected static List<Fx> globalFxs;
// This is the data list we'll use as parameters
protected static List<Dx> globalDxs;
#Parameters
public static Collection<Object[]> data(){
// Instantiate object list for parameters.
// Note: you must do it here and not in, say, #BeforeClass setup()
// e.g.
globalDxs=new ArrayList<Dx>(serverObj.values());
Collection<Object[]> rows=new ArrayList<Object[]>();
for(Dx d:globalDxs) {
rows.add(new Object[]{d});
}
return rows;
}
#BeforeClass
public static void setUp() throws Exception {
// Instantiate/initialize all suite variables/objects to be shares with test classes
// e.g. globalFxs=new ArrayList<Fx>();
}
#AfterClass
public static void tearDown() throws Exception {
// Clean up....
}
}
Next, in test class:
#RunWith(Parameterized.class)
public class JUT_test1 {
// declare local names (if desired) for suite-wide variable/objects
// e.g.
private static List<Fx> globalFxs;
// This is the test parameter:
private Dx d;
public JUT_test1(Dx d){
this.d=d;
}
#Parameters
public static Collection<Object[]> data(){
// Note: we're calling the suite's data() method which has already executed.
return JUTSuite.data();
}
#BeforeClass
public static void setUpBeforeClass() throws Exception {
// (If desired)initialize local variables by referencing suite variables.
// e.g.globalFxs=JUTSuite.globalFxs;
}
}
I agree, it's not possible with the provided classes, but there are workarounds that will get you most of the way there, like #mikemil's.
I've spent some time extending Suite and delegating to Parameterized, with partial success; it is possible to build runner that does what you want, and the code is more-or-less written for you in those two classes. The way those classes interact (in particular, the definition of Parameterized#getChildren()) makes it difficult to extend or delegate to those classes to accomplish what you need, but creating a whole new class than extends ParentRunner and lifts code from the other two would be fairly easy.
I'll try to get more time to come back to this later. If you do build a new runner before I get around to it, please post it as an answer, I'd love to use it myself.
the best solution will be, keep suit classes separately in a blank class.
For example, I am testing logins as Parameterized tests and putting in a suit (for navigation performance measurement)
#RunWith(Suite.class)
#Suite.SuiteClasses({
LoginPageTest.class,
HomePageTests.class})
public class PerformanceTests {
}
and LoginPageTest is actually Parameterizedtests
#RunWith(Parameterized.class)
public class LoginPageTest
{...}
As already stated multiple times, it's not possible to parameterize a test suite with the runners provided by JUnit 4.
Anyway, I wouldn't recommend to make your testclasses dependent from some externally provided state. What if you want to run a single testclass?
I would recommend to make your separate test classes #Parameterized and use a utility class to provide the parameters:
#RunWith(Suite.class)
#SuiteClasses({ Test1.class, Test2.class })
public class TestSuite {
// suite
}
#RunWith(Parameterized.class}
public class Test1 {
public Test1(Object param1) { /* ... */ }
#Parameters
public static Collection<Object[]> data() {
return TestParameters.provideTestData()
}
#Test
public void someTest() { /* ... */ }
}
#RunWith(Parameterized.class}
public class Test2 {
public Test2(Object param1) { /* ... */ }
#Parameters
public static Collection<Object[]> data() {
return TestParameters.provideTestData()
}
#Test
public void someOtherTest() { /* ... */ }
}
class TestParameters {
public static Collection<Object[]> provideTestData() {
Collection<Object[]> data = new ...;
// build testdata
return data;
}
You're right: Both Suite and Parameterized are Runners and only one Runner may be used to run a test at a time. Standard JUnit 4 doesn't provide a combined Runner.
You can either implement your own Runner or have a look at this ready-to-use library which provides a ParameterizedSuite Runner: https://github.com/PeterWippermann/parameterized-suite
A parameterized test suite looks like this:
#RunWith(ParameterizedSuite.class)
#SuiteClasses({OneTest.class, TwoTest.class})
public class MyParameterizedTestSuite {
#Parameters(name = "Parameters are {0} and {1}")
public static Object[] params() {
return new Object[][] {{'A',1}, {'B',2}, {'C',3}};
}
Maybe this answer helps: Parameterized unit test suites
It uses #RunWith(Enclosed.class) and seems to solve the problem.
In JUnit, you can create test suites like so:
public class SecurityTest1 {
#Test
public void testSecurity1() {
// ...
}
}
public class LoadTest1 {
#Test
public void testLoad1() {
// ...
}
}
public class SecurityTest2 {
#Test
public void testSecurity2() {
// ...
}
}
#RunWith(Suite.class)
#SuiteClasses({SecurityTest1.class, SecurityTest2.class})
public class SecurityTestSuite {}
But this seems rather cumbersome. It would be so nice to define a simple class-level annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface SecurityTest {}
And then define your suite like so:
#SecurityTest
public class SecurityTest1 {
#Test
public void testSecurity1() {
// ...
}
}
public class LoadTest1 {
#Test
public void testLoad1() {
// ...
}
}
#SecurityTest
public class SecurityTest2 {
#Test
public void testSecurity2() {
// ...
}
}
#RunWith(Suite.class)
#SuiteClasses({SecurityTest.class})
public class SecurityTestSuite {}
Is this possible? If so how? Note: not interested in switching to TestNG or any other test framework if JUnit does not support this...thanks in advance!
You can do it by implementing your own Test Runner similar to the Suite runner.
This runner should extract the marker annotation class from the value of the #SuiteClasses annotation (you should probably replace #SuiteClasses with your own annotation). Take a look at the getAnnotatedClasses method of the org.junit.runners.Suite class.
After having the marker annotation class, you should scan the classpath for test classes marked with this annotation (use a library such as Reflections) and pass an array of them to the appropriate Runner constructor.
You can find a similar behavior in the Suite constructor:
public Suite(Class<?> klass, RunnerBuilder builder) throws InitializationError {
this(builder, klass, getAnnotatedClasses(klass));
}