My code:
#Component
public class A {
#Autowired
private B b;
public void method() {}
}
public interface X {...}
#Component
public class B implements X {
...
}
I want to test in isolation class A. Do I have to mock class B? If yes, how? Because it is autowired and there is no setter where i could send the mocked object.
I want to test in isolation class A.
You should absolutely mock B, rather than instantiate and inject an instance of B. The point is to test A whether or not B works, so you should not allow a potentially broken B interfere with the testing of A.
That said, I highly recommend Mockito. As mocking frameworks go, it is extremely easy to use. You would write something like the following:
#Test
public void testA() {
A a = new A();
B b = Mockito.mock(B.class); // create a mock of B
Mockito.when(b.getMeaningOfLife()).thenReturn(42); // define mocked behavior of b
ReflectionTestUtils.setField(a, "b", b); // inject b into the B attribute of A
a.method();
// call whatever asserts you need here
}
Here's an example of how I got my tests working with Spring 3.1, JUnit 4.7, and Mockito 1.9:
FooService.java
public class FooService {
#Autowired private FooDAO fooDAO;
public Foo find(Long id) {
return fooDAO.findById(id);
}
}
FooDAO.java
public class FooDAO {
public Foo findById(Long id) {
/* implementation */
}
}
FooServiceTest.java
#RunWith(MockitoJUnitRunner.class)
public class FooServiceTest {
#Mock private FooDAO mockFooDAO;
#InjectMocks private FooService fooService = new FooService();
#Test public final void findAll() {
Foo foo = new Foo(1L);
when(mockFooDAO.findById(foo.getId()).thenReturn(foo);
Foo found = fooService.findById(foo.getId());
assertEquals(foo, found);
}
}
You can inject the field via reflection using Spring's ReflectionTestUtils.setField (or the junit extension PrivateAccessor) or you can create a mock application context and load that. Though for a simple unit (non-integration) test, I favor using reflection for simplicity.
This forum discussion makes sense to me. You can declare your private member b as a type of InterfaceB which is implemented by the class B (ie: service-oriented) then declare a MockB class would also implement the same interface. In your test environment application context, you declare MockB class and your production application context you declare the normal B class and in either case, the code for class A does not need to be changed since it will be auto-wired.
Related
Spring Boot & Java 11 here. I have an abstract base class:
public abstract class AbstractBurninator {
// ...
}
And some subclasses, such as:
public class FizzBurninator extends AbstractBurninator {}
public class BuzzBurninator extends AbstractBurninator {}
public class FoobazBurninator extends AbstractBurninator {}
But there are many more subclasses of it besides those three. I also have an interface:
public interface DoesThings<B extends AbstractBurninator> {
void doAllTheThings(B burninator, String payload);
}
So each implementation of the interface must specify the AbstractBurninator subclass it operates on. Hence I have:
public class DoesFizzThings implements DoesThings<FizzBurninator> {}
public class DoesBuzzThings implements DoesThings<BuzzBurninator> {}
public class DoesFoobazThings imlpements DoesThings<FoobazBurninator> {}
etc.
I now have a Spring Boot service (annotated with #Service) that gets autowired with a list of all List<DoesThings>. Inside that service I have a method that will infer (from certain logic) and instantiate an AbstractBurninator subclass, and it then needs to look up the DoesThings implementation associated with it. Hence if it infers an instance of FizzBurninator, I want it to select the DoesFizzThings instance from the autowired list:
#Service
public class BurninationService {
#Autowired
private List<DoesThings> thingDoers;
public void hahaha(Whistlefeather wf) {
// use 'wf' and other stateful data to infer a subclassed instance of 'AbstractBurninator':
AbstractBurninator burninator = inferSomehow();
// TODO: how to figure out which item of 'thingDoers' matches 'burninator'?
}
What's an easy and elegant way of doing this TBD lookup? I could inject a map instead:
private Map<AbstractBurninator,DoesThings> thingDoers;
But that seems unnecessary since each DoesThing has 1-and-only-1 corresponding AbstractBurninator. Any ideas? It's possible this can be done with straight Java generics, but I'm guessing Spring has some nifty utility that can help here.
If you are comfortable with wiring your Spring context into your service, you could do something like this (inspired by this SO accepted answer)
private <T extends AbstractBurninator> DoesThings<T> getSomeBurn(Class<T> clazz) {
String[] arr = ctx.getBeanNamesForType(ResolvableType.forClassWithGenerics(DoesThings.class, clazz));
if (arr.length == 1) {
return (DoesThings<T>) ctx.getBean(arr[0]);
} else {
throw new IllegalArgumentException("No burninator found");
}
}
This comes with a beautiful "unchecked cast" warning. Also, in my experience, wiring the application context indicates a design problem and definitely complicates testing.
I have created an interface Client with its two concrete implementations
clientA and clientB and annotated them with my custom annotation.
public interface Client{
public void dosomething();
}
#Component
#Myannotation
public class clientA implements Client {
public void doSomething(){
sysout("Client A do something");
}
}
#Component
#Myannotation
public class clientB implements Client {
public void doSomething(){
sysout("Client B do something");
}
}
Now I am calling the overriden methods of both clientA and clientB from Alien class.
#Component
class Alien{
#Autowired
private ApplicationContext context;
public void performOperation(){
Map<String, Object> beans =
context.getBeansWithAnnotation(MyAnnotation.class);
for(Map.Entry<String, Object> entry: beans.entrySet()) {
Client c = (Client)entry.getValue();
c.doSomething();
}
}
}
I am facing problem with writing test method for performOperation.
#RunWith(MockitoJUnitRunner.class)
class AlienTest
{
#InjectMocks
Alien a;
#Test
public void testperformOperation(){
//how to Mock for beans
assertEquals(expected, a.performOperation());
}
}
1) How should I write testperformOperation method(allowed to change the return type of performOperation method from void to any other type)
2) Is there any better way to get list of all implementations for Client interface without creating custom annotations.
I would suggest you first refactoring Alien to make it more testable using Dependency Injection idea which its dependencies (i.e Client) can be injected from outside rather than hard coded inside a method which always get from the spring context:
#Component
public class Alien{
private List<Client> clients = new ArrayList<>();
#Autowired
public Alien(List<Client> clients) {
this.clients = clients;
}
public void performOperation(){
for(Client c: clients) {
c.doSomething();
}
}
}
If you simply want to inject all Client implementation to the Alien , you just need to #Autowired List<Client> into Alien which Spring will already help you to inject all the Client implementation to it out of the box. No need to create #Myannotation
Once you make the Alien 's dependencies injectable (i.e a list of client) , you can simply inject a mock to it and verify performOperation() really invoke all of Client 's doSomething():
#RunWith(MockitoJUnitRunner.class)
class AlienTest{
#Mock
private Client mockClientA;
#Mock
private Client mockClientB;
#Test
public void testperformOperation(){
List<Client> clients = new ArrayList<>();
clients.add(mockClientA);
clients.add(mockClientB);
Alien alien = new Alien(clients);
alien.performOperation();
verify(mockClientA).doSomething();
verify(mockClientB).doSomething();
}
}
I’ll answer both parts of your question, but I believe the first approach is inferior and the second is the go-to approach.
If you want to stick with your custom annotation approach, you need to have a #Mock ApplicationContext applicationContext in your test class. In the test method (or setup method) you need to mock the call to applicationContext.getBeansWithAnnotation and return an appropriate map containing your bean (possibly also a mock)
You can easily inject all beans to a class by injecting a List of the appropriate type. In your case
get rid of #Autowired ApplicationContext
add an #Autowired List (or, preferably, use constructor injection)
This will also make the tests simpler, no need to mock ApplicationContext.
For example, see https://dzone.com/articles/load-all-implementors
I have problem with writing test cases using SPOCK. Could anyone please help me?
I have classes & interfaces like below,
//Helper class
public class ObjClass{
//Defining all property variables & corresponding getters & setters methods.
}
//Interface
public interface B{
//Declaring custom methods for Mongo repository.
public int getId();
}
public interface A extends MongoRepository<ObjClass, Serializable>, B{
//Defining some standard MongoRepository methods here
}
// Implementation Classes
public class Aimpl implements B{
//implementing all B interface methods
}
public class ctrlClass{
#Autowired
A aObj;
public int getIdValue(){
return aObj.getId();
}
}
And below is the corresponding SPOCK test cases:
class test extends Specification
{
ctrlClass obj1
A obj2 //interface class object
def setup(){
obj1 = new ctrlClass();
obj2 = new Aimpl(); //Creating object for interface using impl class.
obj1.aObj = obj2
}
def "test"(){
when:
def a = obj2.getIdValue()
then:
//validating some conditions here with 'a' value
}
}
Getting below error while executing above test case,
Cannot cast object Aimpl to class A.
The same above scenario is working fine with Spring #Autowired. But not in Spock.
*
Is there any alternate available for #Autowired in SPOCK? Please suggest me some solutions & your comments.
*
The problem you have is the ability of Spring to bind the interface with the related implementation.
If your interface has only one implementation and the single implementation has the annotation #Component with Spring's component scan enabled, than Spring framework success to infer the relationship between the interface and its implementation.
In case the component scan is not enabled, then the bean should be explicitly defined in your spring configuration file (such as application-config.xml).
The casting of Aimpl and A cannot succeed because the inheritance classes/interface are different.
You should change the code like the following:
public class ctrlClass{
#Autowired
Aimpl aObj;
public int getIdValue(){
return aObj.getId();
}
}
And in the test class make the following change:
A obj2 //interface class object
Should be changed to:
Aimpl obj2
I have a Java application that uses Spring's dependency injection. I want to mock out a bean, and verify that it receives certain method calls.
The problem is that Mockito does not reset the mock between tests, so I cannot correctly verify method calls on it.
My unit under test:
public class MyClass {
#Resource
SomeClientClass client;
public void myMethod() {
client.someMethod();
}
}
The unit test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = UnitTestConfig.class)
public class MyClassTest {
#Resource
SomeClientClass client;
#Test
public void verifySomething() {
// ...
Mockito.verify(client).publish();
}
}
Finally,
#Configuration
public class UnitTestConfig {
#Bean
SomeClientClass client() {
return Mockito.mock(SomeClientClass.class);
}
}
Though I could hack my way around this problem by manually resetting mocks between tests, I wonder if there's a cleaner / more idiomatic approach.
I had to add this at the start:
#BeforeEach
void setup() {
Mockito.reset(...mockBeans);
...
}
Author not explained why he needs it, I can put more details.
Combining Spring's dependency injection with Mockito in this way not the best approach.
It leads to errors, because same Mocks will be reused between different tests!
This means that verify() will work incorrectly. It will accumulate method invocations from different tests. For example you will get "Wanted 1 time:" - "But was 2 times".
Most generic solution for this in Mockito is using #InjectMocks.
This annotation doing 2 important things:
actually injecting all #Mock fields into class annotated with #InjectMocks
resets each #Mock annotated class. (so, verify() will not accumulate invocations from different tests)
Code example:
#RunWith(MockitoJUnitRunner.class)
public class SomeSpringConverterTest {
#InjectMocks
private SomethingToJsonNodeSpringConverter someSpringConverter;
#Mock
private SomethingDatamodelService someDatamodelService;
#Test
public void convertOriginalContainerTest() {
SomethingContainer someContainer = buildSomeContainer("aa", "bb");
Mockito.when(someDatamodelService.getAttributes()).thenReturn(Arrays.asList("aa", "bb"));
JsonNode node = someSpringConverter.convert(someContainer, JsonNode.class);
Mockito.verify(someDatamodelService.getAttributes());
assertTrue(node.get("aa") != null);
}
#Test
public void convertOriginalContainerTest() {
SomethingContainer someContainer = buildSomeContainer("aa", "bb");
Mockito.when(someDatamodelService.getAttributes()).thenReturn(Arrays.asList("aa", "bb"));
JsonNode node = someSpringConverter.convert(someContainer, JsonNode.class);
Mockito.verify(someDatamodelService.getAttributes());
assertTrue(node.get("bb") != null);
}
}
I'm having an issue when trying to mock a property of a service from within a Junit test:
#ContextConfiguration("classpath:application-config.xml")
#RunWith(SpringJUnit4ClassRunner.class)
public class FooServiceTests {
#Autowired
private FooServiceImpl fooService;
#Test
public void testFoo() {
String str = fooService.foo();
assertEquals("Var", str);
}
#Before
public void mockFooDao() throws Exception {
FooDao mockFooDao = Mockito.mock(FooDao.class);
Mockito.when(mockFooDao.foo()).thenReturn("Var");
ReflectionTestUtils.setField(fooService, "fooDao", mockFooDao);
}
}
Mocking fooDao has no effect since the the result is not the expected. Here is the code of both the service and the dao:
#Service("fooService")
public class FooServiceImpl implements FooService {
#Autowired
protected FooDao fooDao;
#Override
public String foo() {
return fooDao.foo();
}
}
#Repository
public class FooDaoImpl implements FooDao {
#Override
public String foo() {
return "foo";
}
}
As we can see the actual service is meant to return "foo", but the test mocks the dao so the service returns "var". I know it's a CGLIB proxy related thing but I can't figure out how to make it work without using a setter for the fooDao property. Any help would be appreciated.
Regards and thanks in advance.
Short answer
You have to unwrap the proxy and set the field on the target object:
ReflectionTestUtils.setField(unwrapFooService(), "fooDao", mockFooDao);
The unwrapFooService() can be defined as follows:
private FooServiceImpl unwrapFooService() {
if(AopUtils.isAopProxy(fooService) && fooService instanceof Advised) {
Object target = ((Advised) fooService).getTargetSource().getTarget();
return (FooServiceImpl)target;
}
return null;
}
...long one
The problem is quite complex, but solvable. As you have guessed this is a side-effect of CGLIB proxies being used. In principle, Spring creates a subclass of your FooServiceImpl named similar to FooServiceImpl$EnhancerByCGLIB. This subclass contains a reference to the original FooServiceImpl as well as... all the fields FooServiceImpl has (which is understandable - this is a subclass).
So there are actually two variables: FooServiceImpl$EnhancerByCGLIB.fooDao and FooServiceImpl.fooDao. You are assigning a mock to the former but your service uses the latter... I wrote about this pitfalls some time ago.