PowerMockito verifyNew and verifyPrivate are mutually exclusive? - spring

I have a class like this
#Component
public class TestClass {
public void testMethod(){
FinalClass f = new FinalClass("string");
somePrivateMethod(f.getSomeString());
}
private void somePrivateMethod(String s){
}
}
As you can see it has a public method and private method. In public method it is instantiating an instance of FinalClass, which is a class in some third party library and it is final. Lets say it is like this
public final class FinalClass {
private final String someString;
public FinalClass(final String s) {
someString = s;
}
public String getSomeString() {
return someString;
}
}
And Now I am writing unit test for my test class. Since I have to verify final classes and private methods, I am using powermockito. And this is how my test class looks like
#RunWith(PowerMockRunner.class)
#PrepareForTest({TestClass.class, FinalClass.class})
public class TestClassTest {
private TestClass testClass;
private FinalClass finalClass;
#Before
public void setUp() {
finalClass = PowerMockito.mock(FinalClass.class);
testClass = spy(new TestClass());
}
#Test
public void testSomething() throws Exception {
whenNew(FinalClass.class).withAnyArguments().thenReturn(finalClass);
testClass.testMethod();
verifyNew(FinalClass.class);
//verifyPrivate(testClass).invoke("testMethod");
}
}
It works fine. But the problem is the last two statements verifyNew and verifyPrivate are working mutually exclusively. I mean when I comment one of those(doesn't matter which), the test passes. But when both are enabled, the test fails
Does anyone have any idea why this is happening?

Related

How to test GET request with body in Spring RestController?

I have a rest controller like this;
#RestController
#RequiredArgsConstructor
#RequestMapping(PO)
public class PoController {
private final PoService service;
#GetMapping(value = FILTER, produces = APPLICATION_JSON_VALUE)
public ResponseEntity<List<PoDTO>> filter(PoFilterCriteria poFilterCriteria) {
return ok().body(service.getPos(poFilterCriteria));
}
}
And I want to write an unit test for it but I couldn't achieve to mock the service to return list.
This is my poFilterCriteria model;
#Data
public class PoFilterCriteria {
private double hp;
private FilterOperationType hpOperationType;
private double attack;
private FilterOperationType attackOperationType;
private double defense;
private FilterOperationType defenseOperationType;
}
And this is my test;
#WebMvcTest(value = PoController.class)
class PoControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private PoService service;
private PoDTO poDTO;
private List<PoDTO> poDTOList;
#BeforeEach
void setUp() {
poDTOList = new ArrayList<>();
poDTO = new Po();
poDTOList.add(poDTO);
}
#Test
public void filter_success() throws Exception {
PoFilterCriteria poFilterCriteria= new PoFilterCriteria ();
poFilterCriteria.setAttack(40);
poFilterCriteria.setAttackOperationType(GT);
poFilterCriteria.setHp(49);
poFilterCriteria.setHpOperationType(EQ);
poFilterCriteria.setDefense(60);
poFilterCriteria.setDefenseOperationType(LT);
when(service.getPos(poFilterCriteria)).thenReturn(poDTOList);
mockMvc.perform(get(PO + FILTER)
.param("hp", String.valueOf(40))
.param("hpOperationType", String.valueOf(GT))
.param("attack", String.valueOf(49))
.param("attackOperationType", String.valueOf(EQ))
.param("defense", String.valueOf(60))
.param("defenseOperationType", String.valueOf(LT))
.contentType(APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().json(new ObjectMapper().writeValueAsString(poDTOList)));
}
}
But the list that should return with size of 1 is returning empty.
What did I do wrong?
org.mockito.ArgumentMatchers#any(java.lang.Class)
when(service.getPos(any(PoFilterCriteria.class))).thenReturn(poDTOList);
or
org.mockito.ArgumentMatchers#same
when(service.getPos(same(poFilterCriteria))).thenReturn(poDTOList);

How to handle objects created within the method under test

I have the following model classes:
#Data
public class Address {
private String street;
private int number;
}
#Data
public class Person {
private String name;
private Address address;
}
and the following services:
#Service
public class MyService {
private final OtherService otherService;
public MyService(OtherService otherService) {
this.otherService = otherService;
}
public void create() {
Person myPerson = new Person();
myPerson.setName("John");
otherService.synchronize(myPerson);
myPerson.getAddress().setNumber(12);
}
}
#Service
public class OtherService {
public void synchronize(Person person) {
Address address = new Address();
address.setStreet("sample street");
address.setNumber(123);
person.setAddress(address);
}
}
I want to write a unit test for MyService. This is the not working version of the test:
#ExtendWith(SpringExtension.class)
class MyServiceTest {
#Mock OtherService otherService;
#InjectMocks MyService myService;
#Test
void test_create() {
// GIVEN
doNothing().when(otherService).synchronize(any(Person.class));
// WHEN
myService.create();
// THEN
verify(otherService).synchronize(any());
}
}
This fails because the myPerson object is created within the method being tested and therefore I get a NullPointerException when running the test. How could I deal with this issue? should I capture the value passed to the otherService?
There's a little complexity but it's not bad. Replace your doNothing call with something like this:
Mockito.doAnswer(
new Answer<Void>() {
public Void answer(InvocationOnMock invocation) throws Exception {
Person arg = invocation.getArgument(0);
arg.setAddress(new Address());
return;
}
}).when(otherService).synchronize(any(Person.class));

#value not able to read from application.properties in springboot

I am trying to read value from properties file using #value as follows.
#Value("${abc}")
private String abc;
public List<Record> fetchRecords(String label, String predicate) {
System.out.println(abc);
}
but value of abc is coming as null. Whereas when I try to print the same using #PostConstruct, I am getting the expected value.
#PostConstruct
public void postconstruct() {
System.out.println(abc);
}
Any lead why I am not able to get the value in fetchRecords() method?
For reference, here goes the code
#Component
public class AuditRecord {
private String subject;
private String predicate;
private String oldObject;
private String newObject;
private String readOnlyAuthInfo;
#Value("${registry.system.base}")
private String registrySystemContext;
public void record(DatabaseProvider provider) throws AuditFailedException {
System.out.println("---registrySystemContext value showing null here---"+registrySystemContext);
...
}
#PostConstruct
public void postconstruct() {
System.out.println("---registrySystemContext value showing here as expected---"+registrySystemContext);
}
}
The way I am calling is as follows:
#Component
public class RegistryDaoImpl implements RegistryDao {
...
private void addOrUpdateVertexAndEdge(Vertex v, Vertex dbVertex, GraphTraversalSource dbGraph, String methodOrigin){
...
AuditRecord record = new AuditRecord();
record
.subject(dbVertex.label())
.predicate(e.label())
.oldObject(null)
.newObject(existingV.label())
.record(databaseProvider);
}
}
P.S. registry.system.base is in application.yml.
You need to autowire AuditRecord and not use new directly. Only that way you will have your class in Spring's context.
We don't know your exact usage of the class but you might be interested in Spring's FactoryBean.

How do i pass the browser from test to test with Arquillian Drone and Graphene

I'm trying out Arquillian Drone and Graphene and I have the following 2 tests what i want to do is have the second test use the browser from the first tests. but the browser closes after the first test finishes - is there a way to pass the browser to the second test?
#RunAsClient
public class Test1 extends Arquillian{
private final String subscriptionName = "subName";
private final String subscriptionDescription = "description";
#Test(dataProvider = Arquillian.ARQUILLIAN_DATA_PROVIDER)
public void enterSubscriptionName(#InitialPage SubscriptionPage subscriptionPage) {
subscriptionPage.enterName(subscriptionName);
assertEquals(subscriptionName, subscriptionPage.getNameFieldValue());
}
#Test(dataProvider = Arquillian.ARQUILLIAN_DATA_PROVIDER)
public void enterSubscriptionDescription( SubscriptionPage subscriptionPage) {
subscriptionPage.enterDescription(subscriptionDescription);
assertEquals(subscriptionDescription, subscriptionPage.getDescriptionFieldValue());
}
}
I would refactor the above test as shown here to use the SubscriptionPage in the second test.
#RunAsClient
public class Test1 extends Arquillian {
private final String subscriptionName = "subName";
private final String subscriptionDescription = "description";
#Page
SubscriptionPage subscriptionPage;
#Test(dataProvider = Arquillian.ARQUILLIAN_DATA_PROVIDER)
public void enterSubscriptionName() {
Graphene.goTo(SubscriptionPage.class);
subscriptionPage.enterName(subscriptionName);
assertEquals(subscriptionName, subscriptionPage.getNameFieldValue());
}
#Test(dataProvider = Arquillian.ARQUILLIAN_DATA_PROVIDER)
public void enterSubscriptionDescription() {
subscriptionPage.enterDescription(subscriptionDescription);
assertEquals(subscriptionDescription, subscriptionPage.getDescriptionFieldValue());
}
}

Spring Data Rest Repository with abstract class / inheritance

I can't get Spring Data Rest with class inheritance working.
I'd like to have a single JSON Endpoint which handles all my concrete classes.
Repo:
public interface AbstractFooRepo extends KeyValueRepository<AbstractFoo, String> {}
Abstract class:
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(value = MyFoo.class, name = "MY_FOO")
})
public abstract class AbstractFoo {
#Id public String id;
public String type;
}
Concrete class:
public class MyFoo extends AbstractFoo { }
Now when calling POST /abstractFoos with {"type":"MY_FOO"}, it tells me: java.lang.IllegalArgumentException: PersistentEntity must not be null!.
This seems to happen, because Spring doesn't know about MyFoo.
Is there some way to tell Spring Data REST about MyFoo without creating a Repository and a REST Endpoint for it?
(I'm using Spring Boot 1.5.1 and Spring Data REST 2.6.0)
EDIT:
Application.java:
#SpringBootApplication
#EnableMapRepositories
public class Application {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
I'm using Spring Boot 1.5.1 and Spring Data Release Ingalls.
KeyValueRepository doesn't work with inheritance. It uses the class name of every saved object to find the corresponding key-value-store. E.g. save(new Foo()) will place the saved object within the Foo collection. And abstractFoosRepo.findAll() will look within the AbstractFoo collection and won't find any Foo object.
Here's the working code using MongoRepository:
Application.java
Default Spring Boot Application Starter.
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
AbstractFoo.java
I've tested include = JsonTypeInfo.As.EXISTING_PROPERTY and include = JsonTypeInfo.As.PROPERTY. Both seem to work fine!
It's even possible to register the Jackson SubTypes with a custom JacksonModule.
IMPORTANT: #RestResource(path="abstractFoos") is highly recommended. Else the _links.self links will point to /foos and /bars instead of /abstractFoos.
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(value = Foo.class, name = "MY_FOO"),
#JsonSubTypes.Type(value = Bar.class, name = "MY_Bar")
})
#Document(collection="foo_collection")
#RestResource(path="abstractFoos")
public abstract class AbstractFoo {
#Id public String id;
public abstract String getType();
}
AbstractFooRepo.java
Nothing special here
public interface AbstractFooRepo extends MongoRepository<AbstractFoo, String> { }
Foo.java & Bar.java
#Persistent
public class Foo extends AbstractFoo {
#Override
public String getType() {
return "MY_FOO";
}
}
#Persistent
public class Bar extends AbstractFoo {
#Override
public String getType() {
return "MY_BAR";
}
}
FooRelProvider.java
Without this part, the output of the objects would be separated in two arrays under _embedded.foos and _embedded.bars.
The supports method ensures that for all classes which extend AbstractFoo, the objects will be placed within _embedded.abstractFoos.
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class FooRelProvider extends EvoInflectorRelProvider {
#Override
public String getCollectionResourceRelFor(final Class<?> type) {
return super.getCollectionResourceRelFor(AbstractFoo.class);
}
#Override
public String getItemResourceRelFor(final Class<?> type) {
return super.getItemResourceRelFor(AbstractFoo.class);
}
#Override
public boolean supports(final Class<?> delimiter) {
return AbstractFoo.class.isAssignableFrom(delimiter);
}
}
EDIT
Added #Persistent to Foo.java and Bar.java. (Adding it to AbstractFoo.java doesn't work). Without this annotation I got NullPointerExceptions when trying to use JSR 303 Validation Annotations within inherited classes.
Example code to reproduce the error:
public class A {
#Id public String id;
#Valid public B b;
// #JsonTypeInfo + #JsonSubTypes
public static abstract class B {
#NotNull public String s;
}
// #Persistent <- Needed!
public static class B1 extends B { }
}
Please see the discussion in this resolved jira task for details of what is currently supported in spring-data-rest regarding JsonTypeInfo. And this jira task on what is still missing.
To summarize - only #JsonTypeInfo with include=JsonTypeInfo.As.EXISTING_PROPERTY is working for serialization and deserialization currently.
Also, you need spring-data-rest 2.5.3 (Hopper SR3) or later to get this limited support.
Please see my sample application - https://github.com/mduesterhoeft/spring-data-rest-entity-inheritance/tree/fixed-hopper-sr3-snapshot
With include=JsonTypeInfo.As.EXISTING_PROPERTY the type information is extracted from a regular property. An example helps getting the point of this way of adding type information:
The abstract class:
#Entity #Inheritance(strategy= SINGLE_TABLE)
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME,
include=JsonTypeInfo.As.EXISTING_PROPERTY,
property="type")
#JsonSubTypes({
#Type(name="DECIMAL", value=DecimalValue.class),
#Type(name="STRING", value=StringValue.class)})
public abstract class Value {
#Id #GeneratedValue(strategy = IDENTITY)
#Getter
private Long id;
public abstract String getType();
}
And the subclass:
#Entity #DiscriminatorValue("D")
#Getter #Setter
public class DecimalValue extends Value {
#Column(name = "DECIMAL_VALUE")
private BigDecimal value;
public String getType() {
return "DECIMAL";
}
}

Resources