I hope you're doing well, I have a doubt when I try to create a method that can validate some business rules.
In this case, I have a class
public class ValidationUtils {
final List<CreditValidations> creditValidations;
public ValidationUtils(){
creditValidations = Arrays.asList(
new ValidateAge(),
new ValidateSalary()
);
}
public ValidationRs passAllValidations(Client client){
final var validationsFailed = new ArrayList<String>();
boolean validationResult = false;
for (CreditValidations creditValidationClasses : creditValidations){
validationResult = Boolean.logicalXor(creditValidationClasses .validate(client,validationsFailed),
validationResult);
}
final var rs = new ValidationRs();
rs.setSuccessfulValidations(validationResult);
rs.setValidationsFailed(validationsFailed);
return rs;
}
}
this class has a method called "passAllValidations" That method can evaluate each CreditValidation implementation and join their results, Using this code I don't need to create more methods when I have a new validation, only extends the abstraction and create the new Validation class and inject it in the ValidationUtils constructor.
the abstraction and implementation of CreditValidations look like
public abstract class CreditValidations {
protected final String errorCode;
protected CreditValidations(final String errorCode) {
this.errorCode = errorCode;
}
protected abstract boolean validate(final Client client,final List<String> validationsFailed);
protected boolean evaluateValidation(boolean validationResult, List<String> validationsFailed){
if (!validationResult){
setCode(validationsFailed);
}
return validationResult;
}
protected String getErrorCode() {
return this.errorCode;
}
protected void setCode(List<String> failedValidations) {
failedValidations.add(errorCode);
}
}
public class ValidateAge extends CreditValidations {
public ValidateAge() {
super(CreditValidationErrorEnum.ERROR_VALIDATING_AGE.getCode());
}
#Override
public boolean validate(final Client client, List<String> validationsFailed) {
return this.evaluateValidation(client.getAge() >= 18,validationsFailed);
}
}
in summary, my question is referring to the dependency injection in the class ValidationUtils, I don't know if it way is correct or if Spring Framework has some things that help me to inject all of the CreditValidation implementations and avoid using Array.asList(new NewValidationClass()) or another design pattern which can help.
Thanks in advance.
Related
New in JUnit here. I am using JUnit 4 with Mockito. How do I write junit for "if" condition?
Note: I am trying to cover inside the if statement when question is not null. Hopefully my question makes sense.
public class MyClass{
private HttpServletRequest request;
private A a;
private B b;
public void go(String something, String s){
MyQuestion question = Exam.getSubject().getMarks(a.getAId, b.getBId(), something);
if(question !=null){
request.setAttribute(s, question);
}
}
}
// getMarks I do have catching an exception
Here is the snippet:
public class MarksClass{
Public MyQuestion getMarks(long idA, long IdB, String s){
try{
//some code
}catch(Exception e){
throw new SomeException("exception" + e);
}
}
}
Assuming, "getSubject" returns a field with name "subject".
final HttpServletRequest mockedRequest = Mockito.mock(HttpServletRequest.class);
ReflectionTestUtils.setField(myClass, "request", mockedRequest);
final MarksClass mockedMarksClass = Mockito.mock(MarksClass.class);
final MyQuestion mockedResult = Mockito.mock(MyQuestion.class);
Mockito.when(mockedMarksClass.getMarks(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString()).thenReturn(mockedResult);
ReflectionTestUtils.setField(myClass, "subject", mockedMarksClass);
//... rest of the test
Design your class in such a way that testing becomes easy. Or change the design so that it can be tested more easily.
Having global singletons makes testing difficult, if not impossible. The general way forward is to have a class injected with all its external dependencies (DI, dependency injection) or pass the dependencies as arguments to the method.
public class MyClass {
private HttpServletRequest request;
private A a;
private B b;
private final Supplier<Subject> subjectFactory;
public MyClass(final Supplier<Subject> subjectFactory) {
this.subjectFactory = subjectFactory;
}
public void go(String something, String s){
final MyQuestion question = subjectFactory.get().getMarks(a.getAId, b.getBId(), something);
if(question !=null){
request.setAttribute(s, question);
}
}
}
Then in your real code, initialize the class with a method reference to the method on your singleton:
final MyClass myClass = new MyClass(Exam::getSubject);
And in your test inject a test double:
new MyClass(() -> new Subject() {
#Override
public MyQuestion getMarks(…) {
return null;
}
);
Of course, nothing is prevent you from changing the Supplier<Subject> to a Supplier<MyQuestion>, Function<String, MyQuestion>, or a custom interface; and then replacing this with a test double.
#FunctionalInterface
public interface Grader {
MyQuestion getMarks(String idA, String idB, String something);
}
public class MyClass {
private HttpServletRequest request;
private A a;
private B b;
private final Grader grader;
public MyClass(final Grader grader) {
this.grader = grader;
}
public void go(String something, String s){
final MyQuestion question = grader.getMarks(a.getAId, b.getBId(), something);
if(question !=null){
request.setAttribute(s, question);
}
}
}
And then again in your production code vs your test code:
final MyClass production = new MyClass(Exam.getSubject()::getMarks);
final MyClass underTest = new MyClass((a, b, something) -> null);
Providing different implementations of this interface can make your code a bit more expressive:
public class ExamSubjectGrader implements Grader {
#Override
public MyQuestion getMarks(String idA, String idB, String something) {
return Exam.getSubject().getMarks(idA, idB, something);
}
}
public class NullGrader implements Grader {
#Override
public MyQuestion getMarks(String idA, String idB, String something) {
return null;
}
}
MyClass production = new MyClass(new ExamSubjectGrader());
MyClass underTest = new MyClass(new NullGrader());
(both of those are actually singletons, but they could have their own dependencies or state).
And as you can see: you don't even need a heavy mocking library such as Mockito. Good ol' Java can do that just fine.
Find more details in the question Why is my class not using my mock in unit test?
I apologize if this has been answered before but either i don't know the correct verbiage or my google fu is bad.
I have a TestModel class which has the getters and setters for all the tests I use. Then I have a AdditionalTestModel class that extends the TestModel with additional getters and setters for that specific type of tests.
Now I have BuildTest Class that i want to be able to pass TestModel and any extended classes of TestModel.
public static Class<?> buildTest(Class<?> test, Class<?> template)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Class<?> testClass = test.getClass();
Method[] testMethods = testClass.getMethods();
for (Method method : testMethods) {
String name = method.getName();
if (name.startsWith("get")) {
String testMethodType = method.getReturnType().getTypeName();
// additional code removed//
}
}
If instead of Class<?> i was using TestModel it would work for any test that i pass of Class type TestModel. But i want to be able to pass the extended class to this method as well without having to write a method for each extended class. Any recommendations?
Adding information on the models in case it matters.
public class TestModel {
private String testDescription;
private String testName;
private String apiPath;
private String method;
private String expectedTest;
private Map<String, String> header = new HashMap<>();
private Object body;
private String expectedResult;
private String testCaseId;
private String testUUID;
private List testTypes;
public String getTestDescription() {
return testDescription;
}
public void setTestDescription(String testDescription) {
this.testDescription = testDescription;
}
public String getTestName() {
return testName;
}
public void setTestName(String testName) {
this.testName = testName;
}
public String getAPIPath() {
return apiPath;
}
public void setAPIPath(String apiPath) {
this.apiPath = apiPath;
}
public String getExpectedTest() {
return expectedTest;
}
public void setExpectedTest(String testName) {
this.expectedTest = testName;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public Map<String, String> getHeader() {
return header;
}
public void setHeader(Map<String, String> header) {
this.header = header;
}
public Object getBody() {
return body;
}
public void setBody(Object body) {
this.body = body;
}
public String getExpectedResult() {
return expectedResult;
}
public void setExpectedResult(String expectedResult) {
this.expectedResult = expectedResult;
}
public String getTestCaseId() {
return testCaseId;
}
public void setTestCaseId(String testCaseId) {
this.testCaseId = testCaseId;
}
public String getTestUUID() {
return testUUID;
}
public void setTestUUID(String testUUID) {
this.testUUID = testUUID;
}
public List getTestTypes() {
return testTypes;
}
public void setTestTypes(List testTypes) {
this.testTypes = testTypes;
}
}
public class AdditionalTestModel extends TestModel {
#Override public Object getBody() {
return super.getBody();
}
}
Edit: per a request adding the call information here:
#Test(dataProvider = "Default", threadPoolSize = THREADS, timeOut = API_TIME_OUT)
#Description("")
public void sampleTest(AdditionalTestModel testFromDataProvider) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
testSetup(testFromDataProvider);
AdditionalTestModel test = BuildTest.buildTest(testFromDataProvider, template);
Response response = RestAPI.call(test, testEnvironment);
if (null != response) {
ValidateAPIResponse.validateTestModel(test, response);
} else {
Assert.fail("Response is null, probably a bad method.");
}
}
Where testFromDataProvider is passed from a TestNg data provider.
Now LppEdd below already pointed out i could only assign the base class using generics so working on trying it his way, just have not gotten a chance to change things up yet.
Edit: Also realize now my question was bad. Thanks LppEdd. I should have asked How can I get a method to accept an instance of a class and an instance of any extended class
You are close, you just need to use the extends modifier.
If the class passed in as the test and template parameter should be the same exact class type, you can do:
public static <T extends TestModel> Class<T> buildTest(Class<T> test, Class<T> template) { ... }
Otherwise you can do
public static Class<? extends extends TestModel> buildTest(Class<? extends TestModel> test, Class<? extends String> extends TestModel) { ... }
Which will allow different types to be returned and passed in to each parameter.
You can read up on Java generics and wilcards starting here: https://docs.oracle.com/javase/tutorial/java/generics/wildcards.html
Your buildTest method must accept a TestModel class.
You might be looking for something like
public static TestModel buildTest(
final TestModel test,
final TestModel template) {
final Class<? extends TestModel> testClass = test.getClass();
final Method[] testMethods = testClass.getMethods();
for (final Method method : testMethods) {
final String name = method.getName();
if (name.startsWith("get")) {
final String testMethodType = method.getReturnType().getTypeName();
// additional code removed
}
}
// Maybe
return yourNewInstance; // yourNewInstance is a TestModel, or any class extending it
}
The template argument seems unused here (clarify).
What's the wanted return type? (clarify)
Usage example
final TestModel value1 = buildTest(new TestModel(), ...);
final TestModel value2 = buildTest(new AdditionalTestModel(), ...);
This looks to be exactly the same problem as must be solved by test frameworks. For example, see junit (https://junit.org/junit5/).
The core problem is how to obtain the collection of test methods of a class.
A direct solution would be to have the test class be required to answer its test methods, say, Collection<Function<Void, Void>> getTests(); This has several problems, one being that sub-classes must explicitly list their test methods, two being that sub-classes must be careful to add in the test methods from their super-class, and third, this really fits more as static behavior, which would try to shift java instance typing to the class layer, which just isn't supported by java.
An indirect solution would be to require that test methods satisfy a particular pattern (for example, must start with "test" and have no parameters), and use reflection to discover the methods. Or, use an annotation (say, #Test, which is what junit does) to mark out test methods, and again use the java reflection API to discover methods with the marker.
Context
I develop, for my company a software that classifies phishing and malware containing website thanks to multiple feature extraction algorithm.
Once features are extracted we use a pool of empirical and machine learning classifiers. We choose among them thanks to election function of our own.
the code
Basically we have our classifier classes that implement the AnalysisFunction contract.
public abstract class AnalysisFunction {
abstract public StatusType analyze(List<TokenEntity> tokens);
abstract public double getPhishingProbability(List<TokenEntity> tokens);
}
Our pool of classifier is contained by a "pool" that implements AnalysisFunction.
public class PoolAnalysisFunction extends AnalysisFunction{
private final List<AnalysisFunction> candidates;
private final ChoiceFunction choice;
private static final Logger LOG = LogManager.getLogger(PoolAnalysisFunction.class);
public PoolAnalysisFunction(List<AnalysisFunction> candidates, ChoiceFunction choice) {
this.candidates = candidates;
this.choice = choice;
}
#Override
public StatusType analyze(List<TokenEntity> tokens) {
try {
return choice.chooseAmong(candidates, tokens).analyze(tokens);
} catch (ImpossibleChoiceException e){
LOG.fatal("Not enough analysis function.", e);
return StatusType.CLEAN;
}
}
#Override
public double getPhishingProbability(List<TokenEntity> tokens) {
try {
return choice.chooseAmong(candidates, tokens).getPhishingProbability(tokens);
} catch (ImpossibleChoiceException e){
LOG.fatal("Not enough analysis function.", e);
return 0;
}
}
}
To ease the deployment and testing of new function, we want to make our pool fully customizable and instanciate every function by its name. To achieve this purpose we have a key in our property file that is like analysis.pool.functions=com.vadesecure.analysis.empirical.Function1,com.vadesecure.analysis.machine.AutomaticClassifier1.
I want to instantiate my functions thanks to that.
My problem is that those classifiers depend on different things such as custom configuration object and machine learning model.
I would like to inject those dependencies that are already bound in my hk2 injector.
import org.glassfish.hk2.api.Factory;
public class PoolFunctionFactory implements Factory<AnalysisFunction> {
private final PoolAnalysisParameters parameters;
private static final Logger LOG = LogManager.getLogger(PoolAnalysisFunction.class);
#Inject
public PoolFunctionFactory(PoolAnalysisParameters parameters) {
this.parameters = parameters;
}
#Override
public AnalysisFunction provide() {
try {
Class<?> choice = Class.forName(parameters.getChoiceFunctionFQDN());
ChoiceFunction choiceFunction = new PhishingPriorityChoiceFunction(); // default choice
if(choice.getSuperclass().isInstance(ChoiceFunction.class)){
choiceFunction = (ChoiceFunction) choice.newInstance();
}
List<AnalysisFunction> analysisFunctions = new LinkedList<>();
// I want to instantiate here
}
return new PoolAnalysisFunction(analysisFunctions, choiceFunction);
} catch (ClassNotFoundException|IllegalAccessException|InstantiationException e){
LOG.fatal(e, e);
}
return null;
}
#Override
public void dispose(AnalysisFunction analysisFunction) {
LOG.trace(String.format("%s end of life", analysisFunction));
}
}
On example of model-dependant classifier is :
public class SVMF2AnalysisFunction extends AnalysisFunction {
private final SVMContainer modelContainer;
private double probability = 0.0;
private double threshold = 0.9;
#Inject // i build this model in a parallel thread
public SVMF2AnalysisFunction(SVMContainer modelContainer) {
this.modelContainer = modelContainer;
}
#Override
public StatusType analyze(List<TokenEntity> tokens) {
if (modelContainer.getModel() == null) {
return null;
}
probability = modelContainer.getModel().analyse(tokens.stream());
return probability >= threshold ? StatusType.PHISHING : StatusType.CLEAN;
}
#Override
public double getPhishingProbability(List<TokenEntity> tokens) {
return probability;
}
}
How can I achieve those instanciations.
My first approach was to inject the serviceLocator but i found no documentations for doing this and a colleague said me it was not good.
He told be to document myself about proxies but it doesn't seem to be a good thing for me or perhaps I missed something.
You could just configure all this in your binder. This way you don't need to worry about trying to instantiate everything yourself. Just let HK2 do all the work
#Override
protected void configure() {
bindAsContract(PoolAnalysisFunction.class).in(Singleton.class);
bind(choiceFnClass).to(ChoiceFunction.class);
for (Class<AnalysisFunction> analysisFnClass: analyisFnClasses) {
bind(analysisFnClass).to(AnalysisFunction.class).in(Singleton.class);
}
}
Then you can just inject everything into the PoolAnalysisFunction class, without the need to use a factory.
#Inject
public PoolAnalysisFunction(IterableProvider<AnalysisFunction> candidates,
ChoiceFunction choice) {
this.choice = choice;
this.candidates = new ArrayList<>();
candidates.forEach(this.candidates::add);
}
Notice the IterableProvider class. This is an HK2 class for injecting multiple services bound to the same contract.
Or if you want to use the factory, you could, and just inject the functions into the factory. That way you can make the PoolAnalysisFunction class independent of an HK2 classes (i.e. the InjectableProvider).
I have Neo4j unmanaged extension. I want some services to be created as singletons and be available via #Context in my resources.
Something like this:
#Path("/example")
public class ExampleResource {
public ExampleResource(#Context CostlyService costlyService) { // <<---
// use it here
}
}
How this can be achieved?
Neo4j has PluginLifecycle interface that give us possibility to hook into Neo4j server lifecycle and provide our own services for injection blog post.
So, we have service. Let's take this one as example:
public interface CostlyService {
}
public class CostlyServiceImpl implements CostlyService {
public CostlyService() {
// a LOT of work done here
}
//...
}
Now we need to make our own PluginLifecycle implementation:
public class ExamplePluginLifecycle implements PluginLifecycle {
#Override
public Collection<Injectable<?>> start(GraphDatabaseService graphDatabaseService,
Configuration config) {
final List<Injectable<?>> injectables = new ArrayList<>();
return injectables;
}
#Override
public void stop() {
}
}
As you see, injectable list is empty for now. We will add our service there soon.
Important: you must register your PluginLifecycle implementation, so it will be available via SPI:
// file: META-INF/services/org.neo4j.server.plugins.PluginLifecycle
my.company.extension.ExamplePluginLifecycle
This will make your PluginLifecycle discoverable by Neo4j server.
Now we need to create actual injectable. Let's write implementation for Injectable interface:
public final class TypedInjectable<T> implements Injectable<T> {
private final T value;
private final Class<T> type;
private TypedInjectable(final T value, final Class<T> type) {
this.value = value;
this.type = type;
}
public static <T> TypedInjectable<T> injectable(final T value, final Class<T> type) {
return new TypedInjectable<>(value, type);
}
#Override
public T getValue() {
return value;
}
#Override
public Class<T> getType() {
return type;
}
}
This will serve as simple container for our service. Usage:
import static my.company.extension.TypedInjectable.injectable;
injectable(new CostlyServiceImpl(), CostlyService.class);
Now we can add our injectable into PluginLifecycle.
#Override
public Collection<Injectable<?>> start(GraphDatabaseService graphDatabaseService,
Configuration config) {
final List<Injectable<?>> injectables = new ArrayList<>();
injectables.add(injectable(new CostlyServiceImpl, CostlyService.class)); // <<---
return injectables;
}
After this change our CostlyService will be available for our resources via #Context:
#Path("/example")
public class ExampleResource {
public ExampleResource(#Context CostlyService costlyService) {
// use it here
}
// ...
}
Tip: keep your PluginLifecycle's in same package or in subpackage with your resources.
I want to use java interface in a way that i will make a call defining interface in my other class like 'private SoapURL soapURL;' and than i can access any class's method for example : i want to use login:-
private SoapURL soapURL;
SoapUrl = LoginSoap ();
String nameSpace = soapURL.getMethodName();
String url = soapURL.getUrl();
Is there any way to do something like this. I am sorry i am not very good with Object Oriented principles but if there is a solution for my problem i would like to know it. Thanks in advance.
public interface SoapURL {
public String getNameSpace();
public String getUrl();
public String getSoapAction();
public String getMethodName();
public String getTag();
}
LoginSoap class
public class LoginSoap implements SoapURL {
#Override
public String getNameSpace() {
return "https://host.com/MobileWFC/";
}
#Override
public String getUrl() {
return "https://host.com/MobileWFC/MobileWS.asmx";
}
#Override
public String getSoapAction() {
return "https://host.com/MobileWFC/UserControl";
}
#Override
public String getMethodName() {
return "UserControl";
}
#Override
public String getTag() {
return "Login Activity";
}
}
SignUpSoap class
public class SignUpSoap implements SoapURL {
#Override
public String getNameSpace() {
return "https://host.com/MobileWFC/";
}
#Override
public String getUrl() {
return "https://host.com/MobileWFC/MobileWS.asmx";
}
#Override
public String getSoapAction() {
return "https://host.com/MobileWFC/UserRegister";
}
#Override
public String getMethodName() {
return "UserRegister";
}
#Override
public String getTag() {
return "SignUp Activity";
}
}
ResetPasswordSoap class
public class ResetPasswordSoap implements SoapURL {
#Override
public String getNameSpace() {
return "https://host.com/MobileWFC/";
}
#Override
public String getUrl() {
return "https://host.com/MobileWFC/MobileWS.asmx";
}
#Override
public String getSoapAction() {
return "https://host.com/MobileWFC/UserPasswordReset";
}
#Override
public String getMethodName() {
return "UserPasswordReset";
}
#Override
public String getTag() {
return "Forget Password Activity";
}
}
Your implementation looks correct. To make use of it, you can do this in main:
SoapURL reset = new ResetPasswordSoap();
System.out.println(reset.getUrl());
This is a method of minimizing coupling in large systems. And reduces dependency between objects by making use of a common interface for groups of objects that work together. You might be new at Object oriented principles, but you are one step ahead of the game already
To pass it to a function, you do:
public JPanel resetPass(SoapURL reset) {
...
}
// In main:
JPanel resetPassPanel = resetPass(reset);
Just do, for example:
SoapURL example = new LoginSoap();
String a = example.getTag();
a should be equal to "Login Activity"
The main use of Interface is polymorphism, or the ability to perform the same
operation on a number of different objects,
which is exactly what you wanted in your scenario
Your approach is absolutely fine , just a modification needed
private SoapURL soapURL;
//SoapUrl = LoginSoap (); // This line should be replaced with the Below line
soapURL=new LoginSoap();
String nameSpace = soapURL.getMethodName();
String url = soapURL.getUrl();
Since LoginSoap, SignUpSoap,ResetPasswordSoap classes are implemented classes of SoapURL Interface , thus reference variable of SoapURL can store Object of any of these child classes
soapURL=new LoginSoap();//soapURL.someMethod will call method of LoginSoapClass
soapURL=new SignUpSoap();// will call method of SignUpSoap class
soapURL=new ResetPasswordSoap();