Expectations are not recorded for injectable instances - jmockit

Here is my code and I am doing code coverage testing
public class RegisterTest {
#Tested Register register;
#Test
public void testGetStudentName(#Injectable final Student student) {
new NonStrictExpectations(){
{
student.getRollNo();
result="ab1";
}
};
assertEquals(register.getStudentNo(), "ab1");
}
}
I got assertion error for the above testcase because the injectable instance doesnt work here..I dont know y?
Here is my testclass...
Register.class
public class Register {
Student student=new Student();
public String getStudentNo(){
return student.getRollNo();
}
}
Here is my dependency class
Student.class
public class Student {
String name;
int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
How can I resolve that assertion error??

The #Injectable mock used in the test does work. However, it is never injected into the tested object, which instead creates its own Student instance. So, in situations like this you use #Mocked, not #Injectable.
I should point out two other things, though:
Please take notice of the API documentation. The JMockit jar files (even the Maven ones) contain source code precisely to facilitate access to API documentation from any Java IDE.
"Value classes" like Student (which merely contain getters/setters) are not good candidates for mocking. In general, they should not be mocked. Instead, real instances should be used.

Related

I am trying to use Apache Beam' SchemaCreate annotation. The schema is not being inferred

I have been exploring Beam's Schema related functionality. I tried implementing the #SchemaCreate annotation on a POJO and a JavaBean, but the schema is not being inferred. I keep getting the following exception:
Exception in thread "main" java.lang.RuntimeException: Creator parameter arg0 Doesn't correspond to a schema field
at org.apache.beam.sdk.schemas.utils.ByteBuddyUtils$InvokeUserCreateInstruction.<init>(ByteBuddyUtils.java:1398)
at org.apache.beam.sdk.schemas.utils.ByteBuddyUtils$StaticFactoryMethodInstruction.<init>(ByteBuddyUtils.java:1335)
at org.apache.beam.sdk.schemas.utils.POJOUtils.createStaticCreator(POJOUtils.java:242)
I tried the sample code from Beam documentation of SchemaCreate as below. If I change the code to not use SchemaCreate, it works. Sample code from the documentation of SchemaCreate annotation:
#DefaultSchema(JavaBeanSchema.class)
class MyClass {
public final String user;
public final int age;
private MyClass(String user, int age) { this.user = user; this.age = age; }
#SchemaCreate
public static MyClass create(String user, int age) {
return new MyClass(user, age);
}
}
I also overrode the equals() and hashCode() methods, but still no luck.

Paradigm "program to interfaces, not implementations" vs. builder pattern

I like the builder pattern (example https://stackoverflow.com/a/1953567) for various reasons, e. g. the fact that I can work with immutable objects and that I can control the object creation in the way that no invalid objects can be created.
However, I try to follow the paradigm "program to interfaces, not implementations" (example https://stackoverflow.com/a/2697810).
I figured, these two guidelines do not play well together.
If I have an interface Person and a class PersonImpl and a builder PersonImplBuilder that builds a PersonImpl. I now can assure that every instance of PersonImpl is valid and immutable. But every return value and particularly every method parameter in my API uses the interface. So I can not depend on a valid object.
Am I missing something respectively is there another way of combining these two very useful guidelines?
EDIT
Some code to clarify.
In this example the builder is useless in terms of ensuring validity and/or imutability of the object in my API. It does only guarantee that any object of PersonImpl is valid (and by the way that only works because PersonImpl ist declared as final). But I can not control if a client is actually using my safely constructed PersonImpl object or any other implementation of the Person interface.
public interface Person {
LocalDate getBirthday();
}
public final class PersonImpl implements Person {
private final LocalDate birthday;
private PersonImpl(PersonImplBuilder builder) {
this.birthday = builder.birthday;
}
#Override
public LocalDate getBirthday() {
return birthday;
}
}
public class PersonImplBuilder {
private LocalDate birthday;
public LocalDate getBirthday() {
return birthday;
}
public void setBirthday(LocalDate birthday) {
this.birthday = birthday;
}
public PersonImpl build() {
if(birthday.isAfter(LocalDate.now().minusYears(21).minusDays(1))) {
throw new IllegalStateException("Person must be 21 years or above");
}
return new PersonImpl(this);
}
}
// this is my API
public interface PersonService {
void doSomeAdultStuff(Person person);
}
public class PersonServiceImpl implements PersonService {
//...
}
public void maliciousMethod() {
PersonService service = new PersonServiceImpl();
service.doSomeAdultStuff(new Person() {
#Override
public LocalDate getBirthday() {
return LocalDate.now();
}
});
}
You don't use the builder anywhere in your code. If you don't want to your code to use different implementations of the Person class but just your PersonImpl then don't use the interface but the concrete implementation. This way you will be sure that you have only objects build the way you want.
You should consider that a person can be less than 21 years old and still be a "valid" person (A child for example). You can have adult builder and child builder (different implementations) but you still would need to check if you got the right implementation. So maybe you should check in the service if the person has a correct age and not during building the object. Otherwise it should be called Adult and not a Person ;)
The combination of "program to interface" concept and Builder pattern should have no issue. The reason is in your following code:
service.doSomeAdultStuff(new Person() {
#Override
public LocalDate getBirthday() {
return LocalDate.now();
}
});
You wrote a new class that has no name and implements the Person interface (anonymous class). This class is different with PersonImpl class of your code. In your case just remove anonymous class implementation and use new PersonImpl(builder) instead.
service.doSomeAdultStuff(new PersonImpl(builder));

Can I refer to properties directly in entity constructor with EclipseLink?

EclipseLink version is 2.5.1
We've moved from GlassFish web-server to TomCat. This made us switch to static weaving because with TomCat dynamic weaving doesn't really work that easy.
Now that static weaving works, it seems to work quite a bit differently.
If I have an entity which sets some property directly in the constructor:
class Entity {
#Column
private String name;
public Entity() {
name = "something";
}
public String getName() {
return name;
}
}
Long story short this test will fail:
Entity e = new Entity();
assertEquals("something", e.getName()); // e.getName() returns null
This happens because getName(), after weaving, is not returning this.name anymore. Instead it calls a routing for initialization (if it's needed) and (I guess) gets the value of the property from some underlying HashMap.
But constructor is not being weaved, I even have looked into the sources of weaver and seems to be explicitly opting out of this:
/**
* Construct a MethodWeaver and allow it to process the method.
*/
#Override
public MethodVisitor visitMethod(int access, String methodName, String desc, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, methodName, desc, signature, exceptions);
if (!alreadyWeaved) {
// skip constructors, they will not changed
if (!"<init>".equals(methodName) && !"<cinit>".equals(methodName)) {
// remaining modifications to the 'body' of the class are
// delegated to MethodWeaver
mv = new MethodWeaver(this, methodName, desc, mv);
}
}
return mv;
}
The question is, maybe I miss something here? Is it the actual reality with EclipseLink 2.5.1 that you can't use properties directly in entity's own ctor? (and it's not even mentioned anywhere, not googlable at least)
It turns out yes, we can.
But there was a problem that led us to the property being not visible to the getter.
We actually have MappedSuperclass inheritance here and we were shadowing this field in the child class. Essentially this:
class A {
#Column()
protected String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class B extends A {
#Column()
protected String name;
// no #Override here
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
So we were just shadowing the property.

Behaviours of new constructor added by AspectJ ITD

I am currently applying AspectJ to our project, and I found a behavior which is a bit strange to me.
Q1:
I added a new constructor to my current class with inter-type declaration, and found that the class's member variable is not initialized if the new constructor is used to instantiate my class.
For example:
The class which I'll add a new constructor to:
public class Child {
public String name = "John";
public Child(String desc) {
// TODO Auto-generated constructor stub
}
}
The aspectJ code:
public aspect MyTest {
public Child.new(String desc, int num) {
System.out.println("Child Name:" + this.name);
}
}
If I instantiate the Child with the new constructor:
new Child("A child", 5)
the member variable this.name is not initialized as will be done with the original constructor.
But, if I call the original constructor:
new Child("A child")
the member variable this.name will be initialized to "John" as usual
The result:
Child Name:null
Is this a limitation of AspectJ? Is there anyway to resolve this issue?
I don't really want to add the code for member variable initialization to the new constructor.
Q2:
It seems in the newly added constructor, super.method() can not be correctly resolved.
The class which I'll add a new constructor to:
public class Child extends Parent{
public String name = "John";
public Child(String desc) {
}
}
Child extends Parent. Parent has a method init()
public class Parent {
public void init() {
//....
}
}
I add a new constructor for the Child in my aspect.
public aspect MyTest {
public Child.new(String desc, int num) {
super.init();
}
}
The above aspect code will trigger an exception.
Exception in thread "main" java.lang.NoSuchMethodError: com.test2.Child.ajc$superDispatch$com_test2_Child$init()V
at MyTest.ajc$postInterConstructor$MyTest$com_test2_Child(MyTest.aj:19)
at com.test2.Child.<init>(Child.java:1)
at MainProgram.main(MainProgram.java:11)
My workaround is to define another method for my class Child, and indirectly call the super.method() within that method
For example, add a new method that calls super.init() for Child
public void Child.initState()
{
super.init();
}
Now, I can call initState() in the newly added constructor like below:
public aspect MyTest {
public Child.new(String desc, int num) {
this.initState();
}
}
Is this a limitation of AspectJ? Is this the only way to resolve this issue?
Thank you all for your time :)
Foe the first questions, it seems that the lint warning will appear when compiling:
(unless you close the lint warning)
"inter-type constructor does not contain explicit constructor call: field initializers in the target type will not be executed [Xlint:noExplicitConstructorCall]"
Therefore I'd say it's an AspectJ's limitation.
The best way to do this might be call the other constructors of Child in the constructor added by AspectJ
For example:
public aspect MyTest {
public Child.new(String desc, int num) {
this("Hello"); // -> This will call the constructor of Child, and trigger fields initialization
System.out.println("Child Name:" + this.name);
}
}
For the second question, I think it's a bug of aspectJ.
That decompile the woven target byte code will find that the method “com.test2.Child.ajc$superDispatch$com_test2_Child$init()V” will be inserted. It implies this method should be generate by aspectJ, but there is no such method in the byte code.
The code for an ITD introduction is no different that the code that you would add to a class directly. So without member initialization code in your introduced constructor, members will , of course, remain uninitialized. So you need to change you code in Q1 as follows.
public Child.new(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Child Name:" + this.name);
}
As for Q2, it works fine for me.
class Parent {
public void init() {
System.out.println("P.init");
}
}
class Child extends Parent {
}
aspect Intro {
public void Child.init(){
super.init();
System.out.println("C.init");
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
c.init();
}
}
prints:
P.init
C.init
Changing the introduced method to something other than init works too (to match your code).
Regarding your comment: I fail to see what difference you have made in Q1. Sorry, I don't get it.
As for Q2 part of your comment, constructor arrangement works for me:
class Parent {
protected String name;
public Parent(String name) {
this.name = name;
}
}
class Child extends Parent {
int age;
public Child(String name) {
super(name);
}
}
aspect Intro {
public Child.new(String name, int age){
super(name);
this.age = age;
System.out.println("this.name: " + this.name + " this.age: " + this.age);
}
}
prints this.name: myname this.age: 2

Can AspectJ replace "new X" with "new SubclassOfX" in third-party library code?

I am looking at AspectJ to see if perhaps we can use it in our test suite.
We have a rather large third party Java communications library hardwired to use its own classes (which do not implement any interfaces) which in turn mean that we need a physical backend present and correctly configured to be able to run tests.
I am looking at our options for removing this restriction. A possibility would be to create a subclass of the troublesome classes and then ask AspectJ to simply replace "new X" with "new OurSubclassOfX" when loading the third party library, but I am new to AspectJ and from my brief skimming of the documentation this is not a typical use case.
Can AspectJ do this? What would the configuration snippet be?
Yes, this is possible. Let us assume you have a hard-wired class, possibly fetching something from a database, and want to mock it via an aspect:
package de.scrum_master.aop.app;
public class HardWired {
private int id;
private String name;
public HardWired(int id, String name) {
this.id = id;
this.name = name;
}
public void doSomething() {
System.out.println("Fetching values from database");
}
public int getSomething() {
return 11;
}
#Override
public String toString() {
return "HardWired [id=" + id + ", name=" + name + "]";
}
}
Then there is a little driver application using that very class (not an interface):
package de.scrum_master.aop.app;
public class Application {
public static void main(String[] args) {
HardWired hw = new HardWired(999, "My object");
System.out.println(hw);
hw.doSomething();
System.out.println(hw.getSomething());
}
}
The output is as follows:
HardWired [id=999, name=My object]
Fetching values from database
11
Now you define your derived mock class which should replace the original for testing purposes:
package de.scrum_master.aop.mock;
import de.scrum_master.aop.app.HardWired;
public class HardWiredMock extends HardWired {
public HardWiredMock(int id, String name) {
super(id, name);
}
#Override
public void doSomething() {
System.out.println("Mocking database values");
}
#Override
public int getSomething() {
return 22;
}
#Override
public String toString() {
return "Mocked: " + super.toString();
}
}
And finally you define an aspect with a simple pointcut and advice to replace the original value during each constructor call:
package de.scrum_master.aop.aspect;
import de.scrum_master.aop.app.HardWired;
import de.scrum_master.aop.mock.HardWiredMock;
public aspect MockInjector {
HardWired around(int p1, String p2) : call(HardWired.new(int, String)) && args(p1, p2) {
return new HardWiredMock(p1, p2);
}
}
The output changes as desired:
Mocked: HardWired [id=999, name=My object]
Mocking database values
22
You do that once per class and constructor and are fine. In order to generalise the approach you would need joinpoint properties and, depending on how far you want to go, maybe reflection, but this here is pretty straightforward. Enjoy!