I need to write a unit test to test getRequired() method here by passing test data to private constructor private Example(String a, String b). Please help me with this.
public class Example {
private String str1 = null;
private String str2 = null;
public static void main(String[] args) {
Example e = new Example(args[0], args[1]);
String req = e.getRequired();
System.out.println(req);
}
private Example(String a, String b)
{
str1 = new String(a);
str2 = new String(b);
}
private String getRequired()
{
//code using str1 and str2 here
return "success";
}
}
From a black box testing standpoint
This code can't be tested. You can't even instantiate it, so there's no realistic way to go about this. There's no sense in testing something that can't be used like this.
If you want to make it testable, then you have to expose a static method to create instances of it. If that's a singleton or a factory, that's up to you - it's not apparent just from what you're showing us, but at least this would allow you to test the construction of it without really worrying about the private constructor.
You'd also have to make accessors to get at the fields, but make them package-private.
Further, invocations such as new String(String) in this case aren't needed, and may only serve to confuse you. You're passing in a String, so you don't need to create a new one.
Lastly, from a testing standpoint, getRequired() is tough to test; unless it mutates the state of the instance (which, again, you need to use to verify anything), there's no point to test it. It'll only ever return "success".
public class Example {
private String str1 = null;
private String str2 = null;
public static void main(String[] args) {
Example e = new Example(args[0], args[1]);
String req = e.getRequired();
System.out.println(req);
}
private Example(String a, String b) {
str1 = new String(a);
str2 = new String(b);
}
String getStr1() {
return str1;
}
String getStr2() {
return str2;
}
private String getRequired() {
//code using str1 and str2 here
return "success";
}
public static Example getNewInstance(String a, String b) {
return new Example(a, b);
}
}
From a white box testing standpoint
You can only use reflection to get at the private constructor and the fields to verify that they are set.
#Test
public void testExample() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
Constructor<Example> exampleConstructor = Example.class.getDeclaredConstructor(String.class, String.class);
exampleConstructor.setAccessible(true);
Example example = exampleConstructor.newInstance("foo", "bar");
// verify
Field str1 = example.getClass().getDeclaredField("str1");
Field str2 = example.getClass().getDeclaredField("str2");
str1.setAccessible(true);
str2.setAccessible(true);
assertThat("foo", equalTo(str1.get(example)));
assertThat("bar", equalTo(str2.get(example)));
}
It looks like there are two other options.
Typically a private constructor implies that the class can not be sub-classed, and that by design the user of the exported API is not able to call the constructor directly. In this case there could be a public static factory method that would be implemented. This allows for instance control, which is not implemented below.
public static Example newInstance(String a, String b){
return new Example(a, b);
}
The other option, if you must test the constructor directly, is to promote the access modifier to the default, "package private", modifier.
Example(String a, String b){...}
You could add your unit test in the same package and test that way. Upgrading an access modifier from private to default in order to facilitate testing should not be a concern.
Related
Assume the following class:
public class TestClass {
String attr1;
String attr2;
String attr3;
}
and a client code like:
final TestClass testClassA = new TestClass();
testClassA.attr1 = "1";
testClassA.attr1 = "2";
testClassA.attr1 = "3";
final TestClass testClassB = new TestClass();
I would like to find way/method that updates testClassB with all the values of testClassA.
testClassB.updateAll(testClassA)
One such solution would be:
public void updateAll(TestClass testClass) {
this.attr1 = testClass.attr1;
this.attr2 = testClass.attr2;
this.attr3 = testClass.attr3;
}
Now, here comes the thing: I would like to not have to write this method manually for it to be less resilient when e.g. a new attribute is added. In this case I might forget to add it to the update-method.
The solution does not need to assign the values directly, in fact I'd prefer it to call setter methods.
It is also possible for me to use any 3rd party frameworks out there like Lombok. I am looking for something like the #RequiredArgsConstructor, however I need the new object to be updated and not created.
So something like a #RequiredArgsSetter or a Object.updateInto(Object1 o, Object2 o) method, but again, it should not create a new object but simply update all the fields of an existing object.
Bonus points, if it is somehow possible to annotate the fields which should be included or excluded from being set.
I found your question interesting and decided to try it out. Here is a solution using reflection. It looks for fields that match by name and type and which are not excluded by annotation, then sets the values of any matching fields.
Disclaimer: I haven't thoroughly tested this, only lightly. It may need some work. It also doesn't use setter methods but instead just sets the field value.
Attribute copying method:
public class AttrCopy {
public void copyAttributes(Object from, Object to) throws IllegalAccessException {
Map<String, Field> toFieldNameMap = new HashMap<>();
for(Field f : to.getClass().getDeclaredFields()) {
toFieldNameMap.put(f.getName(), f);
}
for(Field f : from.getClass().getDeclaredFields()) {
Field ff = toFieldNameMap.get(f.getName());
f.setAccessible(true);
boolean include = f.getDeclaredAnnotation(AttrCopyExclude.class) == null;
if(include && ff != null && ff.getType().equals(f.getType())) {
ff.setAccessible(true);
ff.set(to, f.get(from));
}
}
}
}
Annotation to exclude fields:
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
public #interface AttrCopyExclude {
}
Test classes:
public class ClassA {
private String attribute1;
private int attribute2;
private int attribute3;
private String attribute4;
private String attribute5;
// toString()
}
public class ClassB {
private String attribute1;
private int attribute2;
private String attribute3;
#AttrCopyExclude
private String attribute4;
private String attribute6;
// toString()
}
Test code:
public class Tester {
public static void main(String[] args) throws IllegalAccessException {
ClassA classA = new ClassA("aaa", 123, 456, "ddd", "eee");
ClassB classB = new ClassB("111", 789, "333", "444", "555");
System.out.println("Before");
System.out.println(classA);
System.out.println(classB);
new AttrCopy().copyAttributes(classB, classA);
System.out.println("After copy A -> B");
System.out.println(classA);
System.out.println(classB);
}
}
Test output:
Before
ClassA{attribute1='aaa', attribute2=123, attribute3=456, attribute4='ddd', attribute5='eee'}
ClassB{attribute1='111', attribute2=789, attribute3='333', attribute4='444', attribute6='555'}
After copy B -> A
ClassA{attribute1='111', attribute2=789, attribute3=456, attribute4='ddd', attribute5='eee'}
ClassB{attribute1='111', attribute2=789, attribute3='333', attribute4='444', attribute6='555'}
Attributes 1 and 2 are copied. 3 is excluded as type does not match. 4 is excluded by annotation. The last is excluded as the name doesn't match.
you might want to use mapstruct to copy between java object. Great example here
In the program I am making, I am trying to get a formatted season name for a given season(formatted so it . I keep the formatted names in an interface, since if I were to use a map, it would be unnecessarily regenerated, since I don't make an instance of TeamBuilder
The Seasons interface:
public interface Seasons {
/*
* Contains a formatted list of seasons.
*
* An interface is being used as an alternative to using a Map in the
* TeamBuilder class, since calling parseTeam would have to build
* mappings for the seasons each time it
* was called. This way, the formatted name can simply be grabbed
*/
final String Skyrise = "Skyrise";
final String Toss_Up = "Toss%20Up";
final String Sack_Attack = "Sack%20Attack";
final String GateWay = "Gateway";
final String Round_Up = "Round%20Up";
final String Clean_Sweep = "Clean%20Sweep";
final String Elevation = "Elevation";
final String Bridge_Battle = "Bridge%20Battle";
final String Nothing_But_Net = "Nothing%20But%20Net";
final String Starstruck = "Starstruck";
final String In_The_Zone = "In%20The%20Zone";
final String Turning_Point = "Turning%20Point";
}
The problem comes when I try to grab these seasons. My TeamBuilder class takes in an argument(String season), which is unformatted. My question is, is there any way that I can use a String argument for a method to get a specific item from an interface? This is the most preferable to using a HashMap, which would needlessly regenerate the same information
All these classes can be found on the Github page for this project.
If you want to do it in a typed way, you can use Enum for this:
enum Season{
Skyrise,Toss_Up, Sack_Attack;
#Override
public String toString() {
switch(this){
case Skyrise: return "Skyrise";
case Toss_Up: return "Toss%20Up";
case Sack_Attack: return "Sack_Attack";
default: return "";
}
}
}
public class main{
public static void printSeason(Seasons seasons){
System.out.println(seasons);
}
public static void main(String[] args) {
Seasons e = Seasons.Skyrise;
printSeason(e);
System.out.println(e);
}
}
Since the compiler internally invokes the toString(), you can pass the argument as a Seasons or a String like my example.
And if you still want to use a map without "unnecessarily regenerated" you can use a static field with static initializer like this:
class Seasons {
private static Map<String,String> map = new HashMap<>();
static {
map.put("Skyrise", "Skyrise");
map.put("Toss_Up", "Toss%20Up");
}
public static String getFormatted(String key){
return map.getOrDefault(key,"");
}
}
class main{
public static void main(String[] args) {
System.out.println(Seasons.getFormatted("Skyrise"));
}
}
Just to integrate on Snoob answer you can have enum with fields, so:
enum Season
{
Skyrise("Skyrise"),
Toss_Up("Toss%20Up"),
Sack_Attack("Sack%20Attack")
;
public final String fancyName;
private Season(String fancyName)
{
this.fancyName = fancyName;
}
}
You really have all the benefits without any drawback.
Java prohibits access of a final static field from an initializer. For example:
public enum Example {
ValueA("valueAA", "valueAB"),
ValueB("valueBA", "valueBB");
final static Map<String, Example> exampleByPropertyA = new HashMap<>();
final String propertyA;
final String propertyB;
Example(String propertyA, String propertyB) {
this.propertyA = propertyA;
this.propertyB = propertyB;
Example.exampleByPropertyA.put(propertyA, this); // <- Not permitted
}
}
However, if the update to the static Map is performed in a separate method that is called by the initializer, this is fine. For example:
public enum Example {
ValueA("valueAA", "valueAB"),
ValueB("valueBA", "valueBB");
final static Map<String, Example> exampleByPropertyA = new HashMap<>();
final String propertyA;
final String propertyB;
Example(String propertyA, String propertyB) {
this.propertyA = propertyA;
this.propertyB = propertyB;
addExample(this);
}
private addExample(Example example) {
Example.exampleByPropertyA.put(example.propertyA, example); // <- Permitted
}
}
Given this context, my question is: Does a call to a member method constitute a "freeze action" or is it indicative to the JVM that the object is, for all intents and purposes, "initialized"? Curious why this makes a difference.
I've done some searching, but haven't found anything that articulates this well.
Thank you in advance!
Does a call to a member method constitute a "freeze action" or is it indicative to the JVM that the object is, for all intents and purposes, "initialized"? Curious why this makes a difference.
The problem is that your class is initialised top to bottom. This means your static fields have not been initialised yet i.e. your Map is null.
Another approach is to add a static initialisation block to be called after everything has been initialised.
static {
for (Example e: values()) {
addExample(e);
}
}
private static addExample(Example example) {
Example prev = exampleByPropertyA.put(example.propertyA, example);
assert prev == null;
}
NOTE: You can see a final variable before it is initialised. This means final can have a before and after value even without using reflection.
public class A {
final String text = getText();
private String getText() {
System.out.println("text= " + text);
return "is set";
}
public static void main(String... args) {
new A().getText();
}
}
prints
text= null
text= is set
Using reflection you can alter final fields even after initialisation though you should avoid doing this unless there is no other option.
The correct way to do what you're trying to do, is to write a static initializer, which runs after all the enums have been created.
Defensive programming: You should also add a simple check to guard against programming errors.
public enum Example {
ValueA("valueAA", "valueAB"),
ValueB("valueBA", "valueBB");
final static Map<String, Example> exampleByPropertyA = new HashMap<>();
static {
for (Example ex : values())
if (exampleByPropertyA.put(ex.propertyA, ex) != null)
throw new IllegalStateException("Duplicate propertyA: " + ex.propertyA);
}
final String propertyA;
final String propertyB;
Example(String propertyA, String propertyB) {
this.propertyA = propertyA;
this.propertyB = propertyB;
}
}
I'm really new to Java and programming in general (~3 weeks of experience) so sorry if this question is obvious for you guys. I tried searching for answers here but couldn't find any that fit my specific problem. And yeah it's for school, I'm not trying to hide it.
Here I'm supposed to write an object method that returns the string contained in the object oj, in reverse. I do know how to print a string in reverse, but I don't know how I should call the object since the method isn't supposed to have any parameters.
import java.util.Random;
public class Oma{
public static void main(String[] args){
final Random r = new Random();
final String[] v = "sininen punainen keltainen musta harmaa valkoinen purppura oranssi ruskea".split(" ");
final String[] e = "etana koira kissa possu sika marsu mursu hamsteri koala kenguru papukaija".split(" ");
OmaMerkkijono oj = new OmaMerkkijono(v[r.nextInt(v.length)] + " " + e[r.nextInt(e.length)]);
String reve = oj.printreverse();
System.out.println(reve);
}
}
class OmaMerkkijono{
private String jono;
public OmaMerkkijono(String jono){
this.jono=jono;
}
public String printreverse(){
//so here is my problem, i tried calling the object in different ways
//but none of them worked
return reversedstringthatdoesnotexist;
}
}
You just need to add this to your "printreverse" method :
new StringBuilder(this.jono).reverse().toString()
With this, when you call the method with the object "oj":
String reve = oj.printreverse();
After the previous line, "reve" must contain the value of the String reversed.
Olet hyvä, moi moi!
To revers a String use StringBuilder and reverse()
public String printreverse(){
return new StringBuilder(jono).reverse().toString();
}
To access private attributes from outside the class you use what are called accessors and mutators, aka getters and setters.
You just need a basic getter that also reverses the string.
public class MyObject {
private String objectName;
MyObject(String objectName) {
this.objectName = objectName;
}
public String getObjectName() {
return objectName; // returns objectName in order
}
public String getReversedObjectName() {
return new StringBuilder(objectName).reverse().toString();
}
public static void main(String[] args) {
MyObject teslaRoadster = new MyObject("Telsa Roadster");
System.out.println(teslaRoadster.getObjectName());
System.out.println(teslaRoadster.getReversedObjectName());
}
}
Output:
Telsa Roadster
retsdaoR asleT
I am experimenting here a bit.
Say I have a class :
static class MyClass {
static String property = "myProperty";
}
and a method:
public static void myMethod0(Class<MyClass> clazz) {
try {
MyClass myClass = clazz.newInstance();
System.out.println (myClass.property);
} catch (Exception e) {
e.printStackTrace();
}
}
and to test it:
public static void main(String[] args ) {
myMethod0(MyClass.class);
}
myMethod0 would work here, however, I am creating a new instance in order to reach the property.
Since the properties are static I should be able to reach them without actually creating any instance. For example as you would do when reaching a static property, ie MyClass.property
To summarize:
Is it possible to reach the static property of MyClass, by having Class clazz = MyClass.class ?
Thanks !
**
EDIT:
**
To put the above in perspective and what I am actually trying to accomplish:
public static class PDF_1 { public static PDF_1 it = new PDF_1();
static String contentType = "application/pdf";
static String fileEnding = "pdf";
}
static void myMethod0(PDF_1 pdf) {
System.out.println(pdf.fileEnding);
}
public enum PDF_2 {it;
static String contentType = "application/pdf";
static String fileEnding = "pdf";
}
static void myMethod1(PDF_2 pdf) {
System.out.println(pdf.fileEnding);
}
public static void main(String[] args ) {
myMethod0(PDF_1.it); // Works fine! However very verbose because of public static PDF_1 it = new PDF_1();
myMethod1(PDF_2.it); // Works fine! Somewhat verbose though because of the "it" keyword
}
The whole idea as to what I am trying to accomplish with this, is that too often do I see people declare lots of strings, ie:
static class Constants {
static String PDF_CONTENT_TYPE = "application/pdf";
static String PDF_FILE_ENDING = "pdf";
static String HTML_CONTENT_TYPE = "text/html";
static String HTML_FILE_ENDING = "html";
}
// There is no way knowing what type the method actually wants. Is it contentType, fileEnding or something entirely different ?
public void myMethod(String str) {
}
What I am trying to achieve is something that would allow you to pass a main class/enum, ie: PDF and the method will itself determine what it will use. The caller will just know what to pass, a PDF or HTML class/enum. I am also looking for something that is this refactor friendly as well. It is also of interest not to complicate the declaration of this creation. I find fully blown enums just as obtrusive as a class, and can be hard to read. The ide a is that I am just grouping the two strings in a parent object "PDF" and "HTML". An enum:
public enum SomeType {
PDF("application/pdf", "pdf"), HTML(...);
String contentType;
String fileEnding;
// Constructor ...
}
Would not allow you to declare a method and specify that this method expects the HTML stuff. Only that the enum type is of type SomeType. There is a risk that "someone" would pass SomeType.PDF to that method. What I am doing with the enum and class seems like a noob solution, and the Java language should provide a feature like this, or does it already?
Does this make sense?
You could use reflection
System.out.println(myClass.getDeclaredField("property").get(null));
The get-method usually requires an instance to get the attribute from, but since property is static, you may pass it a null.
I hope you meant this - I wrote tests with hamcrest - so don't wonder ;)
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
import org.junit.Test;
public class TestEnumEnding {
#Test
public void whenMethod1WithFiletypeHtmlWeShouldGetStringText_Html() throws Exception {
// Arrange
String contentType = null;
// Act
contentType = method1(Filetype.HTML);
// Assert
assertThat(contentType, is("text/html"));
}
#Test
public void whenMethod1WithFiletypePdfWeShouldGetapplication_pdf() throws Exception {
// Arrange
String contentType = null;
// Act
contentType = method1(Filetype.PDF);
// Assert
assertThat(contentType, is("application/pdf"));
}
private static String method1 (Filetype anyFiletype) {
return anyFiletype.getContentType();
}
public enum Filetype {
HTML("html","text/html"), PDF("pdf","application/pdf");
private final String fileEnding;
private final String contentType;
private Filetype(String fileEnding, String contentType) {
this.fileEnding = fileEnding;
this.contentType = contentType;
}
public String getFileEnding() {
return this.fileEnding;
}
public String getContentType() {
return this.contentType;
}
}
}
public enum PDF { it;
static String contentType = "application/pdf";
static String fileEnding = "pdf";
}
static void myMethod1(PDF pdf) {
System.out.println(pdf.fileEnding);
}
public static void main(String[] args ) {
myMethod1(PDF.it); // Works fine! Somewhat verbose though because of the "it" keyword. Not 100% ideal!
}