I need to execute block of code once upon startup on the Spock tests. I cannot use #Autowired in setupSpec() which is default method for such initialisation, however #Beans would not be loaded till that time.
Found on web (dating back to 2015) source :
The behavior is a consequence of the design of Spring's TestContext framework. I don't
see a way to change it without hitting other problems. The situation isn't any different
when using the TestContext framework with JUnit.
It's been 6 years already, is there any clean way to do this? I want to omit dirty workarounds
You are in luck, thanks to #erdi for implementing this in Add support for injection into #Shared fields in spock-spring module, you can try the feature in the Spock Snapshot 2.0 builds, and it will be in the Spock-2.0M5 release. You need to opt-in into #Shared injection via placing #EnableSharedInjection on your specification, also really important, that you read the javadoc and understand the mentioned implications of doing that.
Related
I'm currently thinking about expanding unit tests for a server and a client application. Mockito is already in use and - I think - very well suited for the task at hand. However, as the Mockito documentation itself admits:
Mockito is not an dependency injection framework, don't expect [the #InjectMocks annotation] to inject a complex graph of objects be it mocks/spies or real objects.
The server-side of course already has CDI via annotations at some places, the client will probably be extended in some place to use CDI for JavaSE in the near future. There is/will be a wild mix of field- and constructor-injection + #postconstruct methods, which is already too complicated for Mockito. So I'm looking for something that will allow me to easily use CDI annotations to inject Mockito's mocks/spies/real objects where needed.
Can Mockito's functionality be expanded via plugins or something similar to enable a dependency resolution closer to what is specified by CDI (I don't think I need the full spec, but something closer to it)? Is there another library that integrates with Mockito and JUnit5 that does that?
weld supports this out of the box, specifically by weld-junit. It supports both junit4 and junit5. In both cases one can define producer methods for the required injection points in which one can freely use mockito or powermock or any other mocking mechanism to create mocks which weld then injects into the test object.
If you wish to mock EJB/CDI beans with OpenEJB, you can do it very easily:
http://tomee.apache.org/master/examples/rest-applicationcomposer-mockito.html
cdi-unit and ioc-unit have modules which support that.
Just add
#Produces
#Mock
ClassName mockedObject;
and the framework will make it an injectable Bean.
Because Spring-driven AspectJ LTW is unable to weave classes loaded before Spring initializes, I'm converting a Spring project to pure Aspectj LTW (with the AspectJ weaver java agent).
However, this collaterally enables AOP in our Unit Tests because I need to add AspectJ's agent to the Maven Surefire plugin argLine parameter and to the default TestNG configuration in my team's IDE (IntelliJ IDEA).
This wouldn't be a problem if our Aspects were not dependent on Spring, but some of them actually require Spring beans to be injected in their fields via #Resource notation. As Spring is not started during Unit Tests, that fields will be null and result in NullPointerExceptions.
Even though I could configure two independent executions of the Surefire plugin during the build process: one with the agent and the other without it; this solution would become impractical as each developer would still need to change the IDE's test configuration for unit tests vs other tests that actually require AOP and start Spring, for every independent test execution (i.e. outside of Maven build process).
What would be the best approach in order to solve this problem? Is there any way to disable AspectJ's LTW while still keeping the java agent configuration intact? Or maybe another and more flexible way to configure AspectJ's LTW that doesn't have the problems of Spring-driven AspectJ LTW?
We could argue about whether or not it is a good design decision to make pure AspectJ aspects dependent on Spring magic or if it would be an option to inject mock-ups for your Spring beans into the aspects. Actually a unit test is not a unit test if it requires such a framework. The same is arguably true for aspects.
Anyway, here is a cheap solution: Use if() pointcuts for all relevant advice and make them dependent on whether you are in testing mode or not. The performance overhead will usually be minimal, don't worry. Just give it a try before you say it is too expensive.
Also possible, but more expensive would be to determine if a test class is in the control flow of the currently intercepted joinpoint via cflow() or cflowbelow(). I do not recommend it in this case though.
A third option might be to add another META-INF/aop.xml to the classpath in testing mode which contains a global exclude statement excluding all classes from weaving. The AspectJ documentation explains how multiple aop.xml are merged logically. Probably this option is the best because it does not require you to change your aspects. I have not tried, but I would if you encounter any difficulties and give me a sign.
I recently started as a freelancer on my current project. One of the thing I threw myself on, was the failing Jenkins build (it was failing starting from April 8th, a week before I started here).
Generally speaking, you could see a buttload of DI issues in the log. First thing I did, was get all tests to work in the same way, starting from the same application context.
They also implemented their own "mocking" thing, which seemed to fail to work correctly. After a discussion with the lead dev, I suggested to start using Springockito. (for a certain module, they needed mocking for their integration testing -- legacy reasons, which can't be changed)
Anyway, stuff started failing badly after that. A lot of beans which were mocked in the test, simply weren't mocked, or weren't found or whatever. Typically, it would fail on the loading of the application context, stating that one or another bean was missing.
I tried different stuff and different approaches, but in the end, only the thing I most feared would work: add #DirtiesContext to every single test. Now, the maven build is starting to turn green again, tests start doing what they are supposed to do. But I am reloading the Spring context each and every time, which takes time - which is all relative, since the context is loaded in about 1 - 2 seconds.
A side note to this story is that they've upgraded to Hibernate 4, and thus to Spring 3.2. Previously, they were using an older version of Spring 3. All tests were working back then, and the #DirtiesContext thing was not necessary.
Now, what worries me the most, is that I can't immediately think of an explanation for this weird behaviour. It almost seems that Springs context is dirtied, simply by launching a test which uses #Autowired beans. Not all tests are using Mocks, so it can't be that.
Does this sound familiar to anyone? Has anyone had the same experiences with integration testing with (the latest version of) Spring?
On Stackoverflow, I've found this ticket: How can a test 'dirty' a spring application context?
It seems to pretty much sum up the behaviour I'm seeing, but the point is that we're autowiring services/repositories/..., and that we don't have any setters on those classes whatsoever.
Any thoughts?
Thanks!
To answer my own question, the secret was in the Spring version. We were using Spring 3.1.3, whereas I presumed they were using Spring 3.2 (they were constantly speaking about a recent upgrade of the Spring version).
The explanation was here, a blog post I stumbled over in my hunt to get it fixed: Spring Framework 3.2 RC1: New Testing Features
And a copy paste of the relevant piece:
The use of generic factory methods in Spring configuration is by no means specific to testing, but generic factory methods such as EasyMock.createMock(MyService.class) or Mockito.mock(MyService.class) are often used to create dynamic mocks for Spring beans in a test application context. For example, prior to Spring Framework 3.2 the following configuration could fail to autowire the OrderRepository into the OrderService. The reason is that, depending on the order in which beans are initialized in the application context, Spring would potentially infer the type of the orderRepository bean to be java.lang.Object instead of com.example.repository.OrderRepository.
So, how did I solve this problem? Well, I did the following steps:
create a new maven module
filter out the tests which needed mocking. All the non-mocked test would run normallly in a Spring build, in a separate Failsafe run (I created a base-package "clean", and sorted them out like that)
Put all the mocked tests in a base package called "mocked", and make an additional run in Failsafe for the mocked tests.
Each mocked test is using Springockito, to create the mocks. I'm also using the Springockito annotations, to easily do a #ReplaceWithMock in place. Every mocked test is then annotated with #DirtiesContext, so the context is dirtied after each test, and the Spring context is reintroduced with each test.
The only reasonable explanation that I could give, is that the context is effectively being dirtied, because there is a framework (Springockito) which is taking over the management of the Spring beans from the Spring framework. I don't know if that's correct, but it's the best explanation I could come up with. That, in fact, is the definition of a dirty context, which is why we need to flag it as dirty.
Using this strategy, I got the build up and running again, and all tests are running ok. It's not perfect, but it's working, and it's consistent.
I'm trying to use PowerMock as a library in another application. Is there a way to use it to mock a static method call without using annotations (I'm in Clojure which doesn't really do annotations)
According to powermock support and this blog, I guess there is no way to avoid annotations in test. I guess we need the #PrepareForTest(StaticClass.class) however. So I believe it is not possible to avoid #PrepareForTest atleast. May be I am wrong, but just thought of sharing what I found.
In fact, it's possible, although the way to final solution is painful.
PowerMock runner just initializes test environment in different classloader, in which the classes specified in PrepareForTest annotation are tweaked by Javassist. So assumed you mimic the work of the classloader and call Javassist by yourself, you can achieve the same effect.
As an example, I utilized PowerMock (internals without annotations) to discover name of method for given method reference. Further info can be found on my blog (in Czech, with working examples). I emphasize such an usage is only experimental and not suitable for production usage.
Is is possible to declare mocks using some mocking framework for my own classes declaratively with Spring? I know there are some standard mocks available in Spring, but I'd like to be able to mock out my own classes declaratively too.
Just to check I'm not going about this the wrong way: the idea is to have a pair of JUnit test and Spring config for each integration test I want to do, mocking everything except the specific integration aspect I'm testing (say I had a dependency on two different data services, test one at a time) and minimising the amount of repeated Java code specifying the mocks.
I did it using special context.xml that included the real XML and overwrote definition of the special beans. Id'd be happy to know that there is better and smarter solution but this one worked fine for me.
Seriously - you really dont want to be doing that.
I have seen a number of projects that attempt to do this and i promise that you will end up with
A huge number of spring files, each one slightly different, but you don't know what and why.
Spaghetti code, because the "declarative" definition doesn't allow to figure out that your objects are doing too much, or doing it with the wrong collaborators.
In the system case, there are a number of points at which you can stub out external services...
I would recommend that you read GOOS - It devotes a book to answering this kind of question.
http://www.growing-object-oriented-software.com/
If there is only a few beans that you want to change, and you want to change them for all tests, the you could have a look at the #Primary annotation.
You have to annotate the special class for the tests with #Primary - then it will "override" the real class. -- But use this only if you want to do it for all tests.