I have a classes:
public class Sender {
private final SomeClass firstField;
private final SomeClass secondField;
private Sender(SomeClass firtsField, SomeClass secondField){
this.firstField = firstField;
this.secondField = secondField;
}
}
#RunWith(MockitoJUnitRunner.class)
public class SenderTest{
#Mock
private firstField;
#Mock
private secondField;
}
Everything are looking grade, but looks like it injects the same objects in two fields or something like this. When I am trying to use when(..).thenReturn() for one field it sets data two another and vise verse; And the most strange that it works fine in debug mode. What can you say?
Mockito has some problems with constructor injection of two or more fields of the same type. But it works perfectly if you use setter injection.
So you can refactor "Sender" class like this:
public class Sender {
private SomeClass firstField;
private SomeClass secondField;
public void setFirstField(SomeClass firstField) {
this.firstField = firstField;
}
public void setSecondField(SomeClass secondField) {
this.secondField= secondField;
}
}
Remember that if class has both the constructor and setters, Mockito will choose the constructor for injection and completely ignore setters.
Edit: if you definitely need to use constructor for some reason, you can always mock fields manually instead of using Mockito annotations.
So in your case Sender would stay the same and SenderTest would be like this:
public class SenderTest {
private SomeClass firstField;
private SomeClass secondField;
private Sender sender;
#Before
public void setUp() {
firstField = Mockito.mock(SomeClass.class);
secondField = Mockito.mock(SomeClass.class);
sender = new Sender(firstField, secondField);
}
#Test
public void smokeTest() {
}
}
It depends what SomeClass is itself. It it a data (POJO) object, it's worth to create them in test (and i.e. fill with random generated values).
If it is a service. It can be sign for a architecture problem. why do you need two copies of the same service? Probably it makes sense to do some refactoring.
Related
I have a question, a little bit theoretical:
Assume, I have the following classes :
interface ReportInterface {
void execute();
}
class Report implements ReportInterface {
private final Repository rep;
Report(Repository ref){
this.rep = ref;
}
public void execute(){
//do some logic
}
}
class ReportWithSetter implements ReportInterface {
private final Repository rep;
private String release;
ReportWithSetter(Repository ref){
rep = ref;
}
public void execute(){
if (release == null) throw IlligalArgumentException("release is not specified");
//do some logic
}
public void setRelease(String release){
this.release=release;
}
}
The second report needs an additional parameter release to work properly, but my interface is defined without parameters for execute method, so I work around it with a setter method, so it would look like:
ReportWithSetter rep2 = new ReportWithSetter (rep);
rep.setRelease("R1.1");
rep.execute();
So I don't like this additional rep.setRelease. I looks weird and artificial - a user of this class may be confused, and for example, if I make the class as a singleton bean in Spring, it is a source of potential error, if it is requested for the second time and somebody forgets to trigger rep.setRelease for the second time. Besides putting it into constructor (I want to make it a spring bean), what would be the best practice to handling this situation?
Assuming you are allowed to change the interface, here are a few solutions I can think of:
Solution #1
void execute(Optional<String> release);
or
void execute(#Nullable String release);
and then use them for Report class as execute(Optional.empty()) or execute(null).
Solution #2
void execute(String... release);
and then use it for Report class as execute() and for ReportWithSetter class as execute("R1.1").
Solution #3
Define both void execute(); and void execute(String release); in the interface. Then while implementing, throw UnsupportedOperationException in the method you don't need. For example, in Report class, you would do:
public void execute(){
//do some logic
}
public void execute(String release){
throw new UnsupportedOperationException("Use the overloaded method");
}
You can also make both these methods as default in the interface, so your implementation classes don't have to worry about implementing the unsupported method.
Use whichever is most readable and maintainable for you.
Solution 1: Spring Dependency Injection - Field Injection:
Spring's Dependency Injection works with reflection, so Setter methods are not required.
So if you make your Report class a Spring Bean and use #Autowired to inject another bean, then the Setter method is not required.
It would look like this:
#Component
class ReportWithRelease implements ReportInterface {
#Autowired private final Repository rep;
#Autowired private Release release;
public void execute(){
if (release == null) throw IlligalArgumentException("release is not specified");
//do some logic
}
}
I changed "String release" to "Release release", because making a bean of "String" would be also strange. So the "Release" class would have to contain your "String release".
If "String release" contains only some configured value, which does not change at runtime. Then you can use #Value to read its String value from a properties file.
Solution 2: Spring Constructor Injection:
Constructor injection is another option, which is even more recommended.
Then your Report bean would look like this:
#Component
class ReportWithRelease implements ReportInterface {
private Repository rep;
private Release release;
#Autowired
public ReportWithRelease(Repository rep, Release release) {
this.rep = rep;
this.release = release;
}
public void execute(){
if (release == null) throw IlligalArgumentException("release is not specified");
//do some logic
}
}
Factory method patterns are good if you want to create instances of different classes of same interface.
class MyFactory {
ReportInterface createInstance(Class clazz, String... args) {
if (Report.class.equals(clazz)) {
return new Report();
}
if (ReportWithSetter.class.equals(clazz)) {
return new ReportWithSetter(args[0]);
}
throw new IllegalArgumentException(clazz.getName());
}
}
Spring of course offers autowiring, but introducing #AutoWire should be done for systematic purposes.
Here you can do with a two-stage execute, a factory.
class ReportFactory /*ReportWithSetter*/ {
private final Repository rep;
private final String release;
private final ReportInterface report = ...;
ReportFactory (Repository rep, String release) {
this.rep = rep;
this.release = release;
}
public ReportInterface report() {
return report;
}
}
new ReportFactory(rep, release).execute();
public abstract class MainService<T extends Managed> {
private static final Logger logger = LoggerFactory.getLogger(ContentService.class);
protected final ExecutorService executor;
private final boolean idValidation;
#Autowired
private LockValidator lockValidator;
public MainService() {
this(null, true);
}
public MainService(boolean idValidation) {
this(null, idValidation);
}
public MainService(final ThreadConfig tpConfig) {
this(tpConfig, true);
}
protected MainService(final ThreadConfig tpConfig, final boolean idValidation) {
// Some code
}
The code above works fine. But I have to replace the #Autowired annotation and inject the component via constructor. The problem is when I create this constructor:
public MainService(LockValidation lockValidation) {
this.lockValidation = lockValidation;
}
Instantly, these attributes get errors:
protected final ExecutorService executor;
private final boolean idValidation;
Variable 'executor' might not have been initialized
And of course, I guess that I need to send some parameters into the new constructor. The question is: How Could I refactor this code, using a constructor to inject the component instead of the annotation?
Quick fix:
public MainService(LockValidation lockValidation,ThreadConfig tpConfig,boolean idValidation) {
this(tpConfig,idValidation);
this.lockValidation = lockValidation;
}
You are not following SOLID principles (Dependency Injection) here by initializing executor inside the constructor. Best approach would be to use all argument constructor.
protected MainService(ThreadConfig tpConfig,boolean idValidation,ExecutorService executor,LockValidation lockValidation) {
this.tpConfig=tpConfig;
this.idValidation=idValidation;
this.executor=executor;
this.lockValidation=lockValidation;
/// Some code
}
Finally, I could see that to create a constructor could be a headache because it's probable to make refactors in the constructors. So, I decided to implement an injection via set method like this:
#Autowired
public void setLockValidation(LockValidation lockValidation) {
this.lockValidation = lockValidation;
}
It worked fine
I have a class which is used as a common class in my project. That class has the access to some other core classes which were inject in that class, through which I can call some APIs. So when I need to call an API in a class, I usually Inject this common class and use the specific API. But when I inject the common class in many other classes, all the core classes also get injected even I need to use one or two of that core classes.
This is my common class
public class ApiService {
private StuResource stuResource;
private VendResource vendResource;
private EduResource eduResource;
private RKEResource rKEResource;
private AleResource aleResource;
private GloResource gloResource;
#Inject
public ApiService(StuResource stuResource, VendResource vendResource,
EduResource eduResource, RKEResource rKEResource,
AleResource aleResource, GloResource gloResource) {
this.stuResource = stuResource;
this.vendResource = vendResource;
this.eduResource = eduResource;
this.rKEResource = rKEResource;
this.aleResource = aleResource;
this.gloResource = gloResource;
}
{Methods for call APIs}
}
So I plan to use singleton patter, so that I can create an object of the common class one time and can use that object everywhere in other classes.
Help me in this implementation. How can I implement singleton pattern in this situation.
It's bad idea at all - put all functionality in single place.
Create separate services for each business process, give them required resources only. I.e.
#Component
public class SchoolService {
private StuResource stuResource;
private EduResource eduResource;
private GloResource gloResource;
#Inject
public SchoolService(StuResource stuResource, EduResource eduResource, GloResource gloResource) {
this.stuResource = stuResource;
this.eduResource = eduResource;
this.gloResource = gloResource;
}
{Methods for call APIs}
}
then
#Component
public class PayService {
private VendResource vendResource;
private EduResource eduResource;
#Inject
public ApiService(VendResource vendResource, EduResource eduResource) {
this.vendResource = vendResource;
this.eduResource = eduResource;
}
{Methods for call APIs}
}
and so on.
Each of these classes will be singletons as you want.
This question already has answers here:
How do I test a class that has private methods, fields or inner classes?
(58 answers)
Closed 4 years ago.
I have a class which is used for email validation. The class has two private String fields out of which i have injected the value of one from application.properties.
public class EmailValidation {
private final String someString = "xyz"
#Value("${regex}")
private String emailRegex;
// methods
}
public class EmailValidaitonTest {
private final EmailValidation obj = new EmailValidation();
//missing emailRegex
}
Now i have to write a unit test for this. This class has no dependency, so i just decided to use the new operator in EmailValidationTest class for the class object. Now, i can access the String someString but i cannot have the value of emailRegex since it was injected by Spring. How can i set its value in the test class and i want its value to be same as in my application.properties.
You use ReflectionTestUtils.setField to inject property value in test cases.
public class EmailValidationTest{
private #InjectsMock EmailValidation validation;
private String emailRegexPattern = "^\w+#[a-zA-Z_]+?\.[a-zA-Z]{2,3}$";
#BeforeAll
public void setUp(){
ReflectionTestUtils.setField(validation, "emailRegex", emailRegexPattern);
}
//your test cases over here.
}
It's preferable if you can write unit tests without loading up Spring context. You can have your class set up like this:
public class EmailValidation {
private final String regex;
#Autowired
EmailValidation (#Value("${regex:}") String regex) {
this.regex = regex;
}
}
Now in your test class, you can instantiate your emailValidation class through constructor param.
private final EmailValidation obj = new EmailValidation("myRegex");
As #JB Nizet points out, it's better to have a static final field for valid email regex or just call through a library.
I'm using spring boot & for properties I've placed application.properties inside src/main/resources
From #Controllers & #Services, I'm able to read properties, but from my model pojo & a singleton class, I'm not able to read the values.
My #SpringBootApplication is in com.vehicle & I've not overriden #ComponentScan, so I belive it should read all the underlying packages.
Below is code:
application.properties
vehicle.lift.maxWeight=10
vehicle.lift.error.overWeight=Overweight
vehicle.battery.default=5.0
vehicle.battery.critical.limit=15
vehicle.walk.distance.error=Not able to move
WalkServiceImpl.java (able to read from here)
package com.vehicle.prototype.service.impl;
#Service
public class WalkServiceImpl implements CapabilityService {
#Value("${vehicle.walk.distance.error}")
private String mDistanceError;
#Override
public void performTask(VehicleData vehicleData) {
double distance = vehicleData.getWalkingDistance();
double remainingBattery = vehicleData.getRemainingBattery();
if (remainingBattery < distance) {
vehicleData.setErrorMessage(mDistanceError);
System.out.println(mDistanceError);
} else {
vehicleData.setRemainingBattery(remainingBattery - distance);
}
VehicleUtil.checkBatteryStatus(vehicleData);
}
}
VehicleData.java (Pojo - not able read from here)
package com.vehicle.prototype.model;
public class VehicleData {
private double walkingDistance;
private double liftWeight;
#Value("${vehicle.battery.default}")
private double remainingBattery;
// setters & getters ....
}
VehicleUtil.java (Singleton - not able to read from here)
package com.vehicle.prototype.utils;
public class VehicleUtil {
private static VehicleUtil mInstance = null;
private static Object mLock = new Object();
#Value("${vehicle.battery.critical.limit}")
private static double mCriticalLimit;
#Value("${vehicle.battery.default}")
private static double mTotalPower;
#Value("${vehicle.battery.critical.warning}")
private static String powerWarning;
private VehicleUtil() {
// empty private constructor.
}
public static VehicleUtil getInstance() {
if (mInstance == null) {
synchronized (mLock) {
if (mInstance == null)
mInstance = new VehicleUtil();
}
}
return mInstance;
}
public static void checkBatteryStatus(VehicleData vehicleData) {
double criticalMark = (mCriticalLimit * 100.0f) / mTotalPower;
if (vehicleData.getRemainingBattery() < criticalMark) {
vehicleData.setBatteryCritical(Boolean.TRUE);
System.out.println(powerWarning);
} else {
vehicleData.setBatteryCritical(Boolean.FALSE);
}
}
}
Please let me know how to fix this.
Thank You
You need to inject the properties into a spring-managed bean.
What you can do, is to bundle the properties in a bean like this (see documentation)
#ConfigurationProperties(prefix="vehicle")
public class VehicleProperties {
#Value("${battery.critical.limit}")
private double mCriticalLimit;
#Value("${battery.default}")
private double mTotalPower;
#Value("${battery.critical.warning}")
private String powerWarning;
}
Then, inject the Vehicle Properties into your service and passe them to VehicleUtil:
public class WalkServiceImpl {
#Autowired
private VehicleProperties vehicleProperties;
#Override
public void performTask(VehicleData vehicleData) {
...
VehicleUtil.checkBatteryStatus(vehicleProperties, vehicleData);
}
}
Better yet, I would convert VehicleUtil into a managed-bean
#Component
public class VehicleUtil {
#Autowired
private VehicleProperties vehicleProperties;
}
VehicleData
I'm assuming VehicleData is some business object, passed from the client or that you create yourself, for which they are many instances (not just one singleton). In this case, it wouldn't make sense to convert VehicleData into a managed-bean, and its external dependencies could just be provided to it through its setters:
public class VehicleData {
private double walkingDistance;
private double liftWeight;
private double remainingBattery;
// setters & getters ....
}
Only Instances controlled by Spring are able to get property values injected.
As you have a Spring application you should not write own singleton logic instead of simply annotation VehicleUtil by #Component. This would also make any usages more testable as you can mock it in a test when the util instance is injected.
You cannot inject a value directly to the VehicleData pojo. The property value is mostly a constant during runtime so it can be a default only. You should set the value before exposing in a repo or service or leave it null and use the value instead of the non set property wherever it is used.