My application is an automation testing framework written in groovy/java.
Currently I have 2 variants of its usage:
1) All my tests classes extends from BaseTest class which reads properties, do some other staff like setup and cleanup, but in the main it starts SpringBoot context where the main application to be tested works. It woks perfect, but every time I run any test - spring starting first which is takes up to a minute of my time.
2) I have another class to extend from called ProxyBaseTest class which creates proxy to a running instance of main application (in case I started it manually with gradle in a separate window). It also works good.
The main problem for me is to replace all the time
class SomeTestClass extends BaseTest {
with
class SomeTestClass extends ProxyBaseTest {
and vise versa.
Is there a way to do something like that:
class SomeTestClass extends A {
....
}
Class A {
....
if(applicationIsRunning){
// use/return/extend/replace/??? from ProxyBaseTest
}else{
// use/return/extend/replace/??? from BaseTest
}
}
I can't merge BaseTest and ProxyBaseTest because BaseTest using springbeans, spring context, annotations etc... if I'll be able to merge it - it is going to make anyone mad after.
3 different ways to do it. The key words to look for are:
Annotations: Don't subclass from a base test class. Annotate the class instead. E.g. jUnit went from subclassing to annotations.
Delegation: Your base class A is an example, where the use/return/extend/replace/??? is a method call to the class actually doing the work.
Composition: Instead of subclassing from a Test class, the code should obtain a reference to the appropriate test class and store it as a field, so you can call whatever method you need. The two test class implementations should then implement a common interface, which is the type of the field.
Related
I have a simple app that uses CDI (I'm developing in Intellij IDE).
The initialization uses a producer
#Produces
public #Alg int getExperimentSize() {
return 1000;
}
I would like to have two configurations for two separate main files (let's say one with 1000 and one with 100). This results in an "Ambiguous dependencies" error. I tried making the producers private and also move the main files to different packages, but they are still visible to one another and the error persists.
Is it possible to run two different main functions with different injections on the same Intellij project?
Edit: Following a comment from #Smutje, I give a more elaborate example:
Assume we have an interface
public interface SortingAlgorithm <T extends Comparable<T>>{
void sort(T[] array);
}
Class AlgorithmRunner gets injected with such an attribute
public class AlgorithmRunner {
#Inject #Quad
SortingAlgorithm quadraticAlgorithm;
}
Team A develops a class implementing the interface
public class BubbleSort implements SortingAlgorithm{
}
and injects it using a producer
#Produces
private #Quad
SortingAlgorithm makeQuadSortingAlg() {
return container.instance().select(BubbleSort.class).get();
}
Team B, which is not aware of team A, has its own implementation and would like to add a corresponding producer. I would like to illustrate this situation in my intellij project.
Is there a reason you want to have two separate Java classes being producers?
In situations like these, when I want to support configurable behaviour I usually would have one producer that produces the configuration and that loads its configurations from e.g. a properties file on #PostConstruct - so I have a single producer (no ambiguous dependencies) but also no hard-coded values.
I need to schedule a task and I'm using EJB #Schedule to do so. It's working fine, however I thought I might try to generalize my design so that I can extend from some abstract scheduler, inherit certain functionality, and specify additional functionality in the sub classes extending the abstract class. This way, when I need additional schedulers that perform similar actions, I don't have to rewrite a bunch of code. I wrote it, didn't get any errors, and I thought all was well, and then when I tried to restart my server,
I got:
EJB class com.schedule.SubmissionScheduler must not be defined as abstract : mcftEAR#mcftWeb.war#SubmissionSchedule in the console.
Maybe I don't know enough about how the #Schedule annotation works, but I can't think of any reason abstract classes won't be allowed for this. Any insight would be appreciated
import java.util.List;
import javax.ejb.Schedule;
import javax.ejb.Stateless;
public abstract class SubmissionScheduler {
public abstract SubmissionScheduler getInstance();
#Schedule(hour= "0")
public void every24Hours() {
// Pull all forms and submit every 24 hours
List<Form> forms = getFormsThatAreReadyForSubmission();
// Loop through the list of forms and submit
if (forms != null || !forms.isEmpty()) {
for (Form form : forms) {
form.getFormDao().submit());
}
}
}
...Then I have another class which extends this one.
EDIT: In addition to not being able to make it an abstract class, it won't allow for the class to be final either...Why??
Basically you need an instance of your bean to run any function - in your case scheduled function.
It is impossible to run a function from abstract class cause it's abstract - a container cannot create instance to run your code. So it have to be non abstract to create instance and run a method.
I have inherited from others a big project of testing whose main Java classes are CommonSteps, CommonBase and CommonScript. They are currently related in this way:
CommonSteps extends CommonBase
CommonBase extends CommonScript
The problem is with the next method when I try to run the project with mvn clean install:
#After
public void tearDown(Scenario scenario) {
if (scenario.isFailed()) {
// Take a screenshot...
final byte[] screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
scenario.embed(screenshot, "image/png"); // ... and embed it in the report.
}
}
I get the error:
cucumber.runtime.CucumberException: You're not allowed to extend classes that define step definitions or hooks: steps.CommonSteps extends class common.CommonBase.
How could I start working with dependency injection deleting everything related to inheritance?
Cucumber creates a new instance of all classes defining stepdefs before each scenario.
It then invokes stepdef methods on one of those instances whenever it needs to run a step.
If you defined a stepdef method foo in class A and you have a class B extends A you'd get an a and b instance.
The foo method would be available on both instances, and Cucumber would not be able to decide what instance to invoke the method on.
That's why we don't allow it.
The solution is to use composition instead of inheritance. You can achieve composition with dependency injection - Cucumber supports several popular DI frameworks.
As has been stated, Cucumber does not allow you to extend step definition base classes. I have just hit this error attempting to re-use a suite of step defs across two different integration test profiles (app is SpringBoot+Java8 but crucially, we write our Cucumber Step definitions in Groovy..).
The solution / workaround I found was to define the common, re-usable, annotated step definitions in a Groovy trait, then have one or more concrete classes implement that trait and simply define / override any behaviour from the trait and most importantly, declare the Spring int-test profile I want to run with. This seems to work well.
you can define your #Before or #After steps in stepdefinition and then add method in base class
stepdefinition:
#After
public void after(Scenario scenario) {
this.scenario = scenario;
}
baseclass method:
public static Scenario scenario;
public Scenario tearDown(Scenario scenario){
if (scenario.isFailed()) {
final byte[] screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.BYTES);
scenario.embed(screenshot, "image/png");
}
return scenario;
}
I had the same problem and solved it following the approach described here.
Use PicoContainer to achieve dependency injection and share state.
Here you can find the latest version considering the date of this post: https://mvnrepository.com/artifact/io.cucumber/cucumber-picocontainer/7.2.3
You just need to add the PicoContainer's dependency and that's it. No configuration is needed.
I've used constructor dependency injection. I don't know if PicoContainer supports other kinds of dependency injection, like a setter method or annotations.
Considering the classes that you have mentioned, when applying dependency injection they should be like the below example:
public class CommonScript {
}
public class CommonBase {
private final CommonScript commonScript;
public CommonBase(CommonScript commonScript) {
this.commonScript = commonScript;
}
}
public class CommonSteps {
private final CommonBase commonBase;
public CommonSteps(CommonBase commonBase) {
this.commonBase = commonBase;
}
}
Following the above structure, you can:
create step definitions and reuse them in your ".feature"
files;
define hooks;
share state;
Reference:
https://cucumber.io/docs/cucumber/state/
https://cucumber.io/blog/bdd/polymorphic-step-definitions/
I want for my Spring Boot test to use new instances for beans for each test run. Which part of the test configuration can I set it?
You may wanna take a look at the #DirtiesContext annotation. Once state of the bean will be modified, new context will be provided:
There are few options to run with, namely:
Before current test class: when declared at the class level with class mode set to BEFORE_CLASS
Before each test method in current test class: when declared at the class level with class mode set to BEFORE_EACH_TEST_METHOD
Before current test method: when declared at the method level with method mode set to BEFORE_METHOD
After current test method: when declared at the method level with method mode set to AFTER_METHOD
After each test method in current test class: when declared at the class level with class mode set to AFTER_EACH_TEST_METHOD
After current test class: when declared at the class level with class mode set to AFTER_CLASS
for further reading, please take a look at:
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/test/annotation/DirtiesContext.html
You can use #DirttiesContext like pezetem wrote.
But if you must have fresh instances of beans for test try refactor your tests and maybe code because you probably will have problems with working app.
Assume that interface for is defined
interface Foo {
int getBaz();
void doBar();
}
Further assume that the contract states that everytime doBar is called baz is incremented. (Ok this is a contrived bit of code but stick with me here)
Now I want to provide a unit test that I can provide to Foo implementers so that they can verify that they meet all the contract conditions.
class FooTest {
protected Foo fooImpl;
#Test
public void int testBazIncrement()
{
int b = fooImpl getBaz();
fooImpl.doBar();
Assert.assertEquals( b+1, fooImpl.getBaz();
}
}
What are the best practices for making the test available to the implemnters of Foo? It seems to me that there needs to be a mechanism for them to call the FooTest and provide a Foo or a FooFactory to construct Foo instances. Furthermore, if there are many tests (think big interface) then I want to put all those tests in one FooTest class.
Are there any best practices for how to implement such tests?
This is a textbook example of Dependency Injection. If you use Spring as the DI container, you can wire in the fooImpl
#Inject
protected Foo fooImpl;
Your test needs to be annotated with #RunWith(SpringJUnit4ClassRunner.class), and it's up to the interface provider to configure Spring with their implementation.
Without a DI container, you can just create an abstract test class with all the tests in it and an abstract method to provide the implementation object.
protected abstract Foo createFoo();
It's up to the implementation provider to subclass the test and implement the abstract method.
class FooImplTest extends FooTestSuper {
#Override
protected Foo createFoo() {
return new FooImpl();
}
If you have multiple tests, consider JUnit's #Suite annotation. It's compatible with the Spring test runner.
You can implement a testDataFactory where you istance your objects, or use GSon for create your objects (personally, I like GSon, is clear and fast, you learn it in a few time).
For the test implementation, I suggest to write more tests and not a single one.
In this way, unit test can be indipendent and you can segregate your problems in a closed structure.
Sonar
Sonar is a tool that help you a lot, making analisys of your code. You can see from sonar front-end how you application is tested:
sonar unit test
as you can see, Sonar can show you where your code is tested or not
Why not just have, say, a InterfaceTester that gets called from the unit tests InterfaceImplATest, InterfaceImplBTest, etc?
e.g.
#Test
public void testSerialisation()
{
MyObject a = new MyObject();
...
serialisationTester.testSimpleRoundTrip(a);
serialisationTester.testEdgeCases(a);
...
}
After much pondering and some dead-ends I have begun using the following pattern:
In the following:
[INTERFACE] refers to the interface being tested.
[CLASS] refers to the implementation of the interface being tested.
Interface tests are built so that developers may test that implementations meet the contract
set out in the interface and accompanying documentation.
The major items under test use an instance of an [INTERFACE]ProducerInterface to create the instance of the object being tested. An implementation of [INTERFACE]ProducerInterface must track all the instances created during the test and close all of them when requested. There is an Abstract[INTERFACE]Producer that handles most of that functionality but requires a createNewINTERFACE implementation.
TESTS
Interface tests are noted as Abstract[INTERFACE]Test. Tests generally extend the Abstract[INTERFACE]ProducerUser class. This class handles cleaning up all the graphs at the end of the tests and provides a hook for implementers to plug in their [INTERFACE]ProducerInterface implementation.
In general to implement a test requires a few lines of code as is noted in the example below
where the new Foo graph implementation is being tested.
public class FooGraphTest extends AbstractGraphTest {
// the graph producer to use while running
GraphProducerInterface graphProducer = new FooGraphTest.GraphProducer();
#Override
protected GraphProducerInterface getGraphProducer() {
return graphProducer;
}
// the implementation of the graph producer.
public static class GraphProducer extends AbstractGraphProducer {
#Override
protected Graph createNewGraph() {
return new FooGraph();
}
}
}
SUITES
Test suites are named as Abstract[INTERFACE]Suite. Suites contain several tests that excersize all of the tests for components of the object under test. For example if the Foo.getBar() returned an instance of the Bar interface the Foo suite includes tests for the Foo iteself as well as running the Bar tests the Bar. Running the suites is a bit more complicated then running the tests.
Suites are created using the JUnit 4 #RunWith(Suite.class) and #Suite.SuiteClasses({ })
annotations. This has several effects that the developer should know about:
The suite class does not get instantiated during the run.
The test class names must be known at coding time (not run time) as they are listed in the annotation.
Configuration of the tests has to occur during the static initialization phase of class loading.
To meet these requirements the Abstract[INTERFACE]Suite has a static variable that holds the instance of the [INTERFACE]ProducerInterface and a number of local static implementations of the Abstract tests that implement the "get[INTERFACE]Producer()" method by returning the static instance. The names of the local tests are then used in the #Suite.SuiteClasses annotation. This makes creating an instance of the Abstract[INTERFACE]Suite for an [INTERFACE] implementation fairly simple as is noted below.
public class FooGraphSuite extends AbstractGraphSuite {
#BeforeClass
public static void beforeClass() {
setGraphProducer(new GraphProducer());
}
public static class GraphProducer extends AbstractGraphProducer {
#Override
protected Graph createNewGraph() {
return new FooGraph();
}
}
}
Note that the beforeClass() method is annotated with #BeforeClass. the #BeforeClass causes it to be run once before any of the test methods in the class. This will set the static
instance of the graph producer before the suite is run so that it is provided to the enclosed tests.
FUTURE
I expect that further simplification and removal duplicate code can be achieved through the use of java generics, but I have not gotten to that point yet.
Here are some of my thoughts about how to make a qualified unit test:
First of all, try to make your a implementer class fully tested, which means all of its methods should be covered by the UT. Doing this will save you a lot of time when you need to refactor your code. For your case, it could be :
class FooTest {
protected Foo fooImpl;
#Test
public void testGetBaz() {
...
}
#Test
public void testDoBar() {
...
}
}
You will find you need to check the internal state of your class and there is nothing wrong it for UT should be a kind of white-box test.
Second, all methods should be tested separately and not depend on each other. In my opinion, for your code posted above, it looks like more than a function test or an integration test, but it's also necessary.
Third, I don't think it's a good practice to use spring or other container to assemble the target object for you, which will make your test running relatively slow, especially when there a load of tests to run. And your class should intrinsically be pojo and you can complete the assembling in another method in your test class if your target object is really complex.
Fourth, if the parent interface of some class is really big, Dividing the test methods into several groups is something you should do. Here is more info.