Below Is a Junit test class I have written. I am wondering how it would be possible to test the boundaries of each class.
public class TestLibrarySearch {
// Test data structures - books, etc
// some books
Book b1, b2, b3;
String authorB1, authorB2, authorB3;
String ISBNB1, ISBNB2, ISBNB3;
String titleB1, titleB2, titleB3;
int ratingB1, ratingB2, ratingB3;
// the array list of books structure
ArrayList<Book> arrayList;
#Before
public void setUp() throws Exception {
// create some books with test data
authorB1 = "B1Author";
authorB2 = "B2Author";
authorB3 = "B3Author";
titleB1 = "B1Title";
titleB2 = "B2Title";
titleB3 = "B3Title";
ISBNB1 = "ISBNB1AAAA";
ISBNB2 = "ISBNB2AAAA";
ISBNB3 = "ISBNB3AAAA";
ratingB1 = 1;
ratingB2 = 1;
ratingB3 = 3;
// create the test book object
b1 = new Book(ISBNB1, authorB1, titleB1, ratingB1);
b2 = new Book(ISBNB2, authorB2, titleB2, ratingB2);
b3 = new Book(ISBNB3, authorB3, titleB3, ratingB3);
// create the array list of books
arrayList = new ArrayList<Book>();
// add the book to the list
arrayList.add(b1);
arrayList.add(b2);
arrayList.add(b3);
}
For example in the below class, the method allows for a search of a book using a certain rating. (1-5), how would I implement a test that also searches outside of the limits, Would this be testing for an exception?
#Test
public void testSearchByRating() {
LibrarySearch ls = new LibrarySearch(arrayList);
ArrayList<Book> results = ls.searchByRating(1);
if ((results.contains(b1)) && (results.contains(b2))){
assertTrue(true);
} else {
assertTrue(false);
}
}
}
In my opinion you have too much setup and an assertion that is not very clear.
Having an if statement in a test is a smell.
refactoring out the if statement leaves the test with:
#Test
public void testSearchByRating() {
LibrarySearch ls = new LibrarySearch(arrayList);
ArrayList<Book> results = ls.searchByRating(1);
assertTrue(results.contains(b1) && results.contains(b2));
}
Actually you could include the neccassary setup here so you have the essence of what you are testing at a glance. Additionally beware of magic numbers. you want to be clear that the rating in the book corresponds to the rating you are searching for.
#Test
public void testSearchByRating() {
//setup/given
int rating = 1;
// if the ISBN is a key, specify 2 different strings, if not use a constant
// if the structure of the ISBN is not checked, prefer a String like "isbn 1"
Book b1 = new Book("ISBNB1AAAA", ANY_AUTHOR, ANY_TITLE, rating);
Book b2 = new Book("ISBNB2AAAA", ANY_AUTHOR, ANY_TITLE, rating);
LibrarySearch ls = new LibrarySearch(Arrays.asList(b1,b2));
// execution/when
ArrayList<Book> results = ls.searchByRating(rating);
// assertion/then
assertTrue(results.contains(b1));
assertTrue(results.contains(b2));
}
If you want to test for searches with an illegal rating, consider the desired behaviour.
This could be one of the following:
#Test(expected=IllegalArgumentException.class)
public void searchForNegativeRatingThrows() {
LibrarySearch ls = new LibrarySearch(Collections.emptyList());
ls.searchByRating(rating);
}
#Test
public void searchForNegativeRatingYieldsNothing() {
int rating = -1;
LibrarySearch ls = new LibrarySearch(Arrays.asList(bookWithRating(rating)));
ArrayList<Book> results = ls.searchByRating(rating);
assertEquals(0, results.size());
}
you could do parameterized tests for this kind of things, but I think it does more harm than good for simple boundary tests (which should be about 4 tests).
Related
This is mainly a question intended for me to learn about various performant ways of filtering and assigning objects to Lists.
Assume
public class A implements Comparable<A> {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#Override
public int compareTo(A o) {
return o.getId().compareTo(this.getId());
}
}
public class B implements Comparable<B>{
private String id;
private List<A> aList = new ArrayList<>();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void addA(A a)
{
aList.add(a);
}
#Override
public int compareTo(B o) {
return o.getId().compareTo(this.getId());
}
}
public class Main {
public static void main(String[] args) {
SortedSet<A> aSet = new TreeSet<>();
SortedSet<B> bSet = new TreeSet<>();
for(int i=0;i<100000;i++)
{
UUID uuid = UUID.randomUUID();
String uuidAsString = uuid.toString();
A a1 = new A();
a1.setId(uuidAsString);
aSet.add(a1);
A a2 = new A();
a2.setId(uuidAsString);
aSet.add(a2);
B b = new B();
b.setId(uuidAsString);
bSet.add(b);
}
//this is where the performance part comes in
//scenario: For each B I want to find A whose Id matches B's Id, and assign it to B
//assume B can have 1-5 instances of A (even though for this example I only initialized 2)
bSet.parallelStream().forEach(b -> {
aSet.parallelStream().filter(a -> {
return b.getId().equals(a.getId());
}).forEach(a -> {
b.addA(a);
});
});
}
}
The solution I came up with was to combine parallelstreams and filters to find the matching IDs between the two types of objects and then to loops through the filtered results to add the instances of A to B.
I used TreeSets here because I thought the ordered IDs might help speed things up, same reason I used parallelStreams.
This is mostly abstracted out from a scenario from a project I am doing at the office which I cant post here. The classes in the actual project have a lot more variables, and in the worst case - have sublists of lists (I resolved that using flatMaps in streams).
However my inexperienced gut tells me there is a more performant way to solve this problem.
I am primarily looking for practical ways to speed this up.
Some ways I thought of speeding this up:
Switch the lists and sets to Eclipse Collections
Assuming the starting point of these classes are CSV files -> Maybe write an apache spark application that will map these(I assumed that Spark could have some internal clever way of doing this faster than Streams).
I dunno......write them all to sql tables....map them via foreign keys and then query them again?
Speed is the name of the game, solutions using vanilla java, different librarys (like Eclipse Collections), or entire engines like Spark are acceptable
Assume the minimum list size is atleast 50,000
Bonus complexity: You can add another class 'C', with multiple instances of 'B' in it. My inexperienced self can only think of writing another similar streaming operation as A->B and run it after the first stream is done. Is there a way to combine both A->B and B->C operations together so that they happen at once. That will definitely speed things up.
Sorry about my inexperienced self and sorry again if this is a duplicate too
In your code, you use b.addA(a); where b is an instance of B while B doesn't have a method addA(A). Is B supposed to keep a list of A's?
However, the answer to your question is hashing. You are looking for a multimap, to be specific. As a quick fix you can use a TreeMap that stores a List of A's by their id:
public static void main(String[] args) {
TreeMap<String, ArrayList<A>> aSet = new TreeMap<>();
ArrayList<B> bSet = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
UUID uuid = UUID.randomUUID();
String uuidAsString = uuid.toString();
A a1 = new A();
a1.setId(uuidAsString);
ArrayList<A> list = aSet.get(a1.getId());
if (list == null) {
list = new ArrayList<>();
aSet.put(a1.getId(), list);
}
list.add(a1);
A a2 = new A();
a2.setId(uuidAsString);
list = aSet.get(a2.getId());
if (list == null) {
list = new ArrayList<>();
aSet.put(a2.getId(), list);
}
list.add(a2);
B b = new B();
b.setId(uuidAsString);
bSet.add(b);
}
for (B b : bSet) {
System.out.println(aSet.get(b.getId()));
}
}
Please note that this isn't a good implementation and instead you should write your own multimap or use the one in guava
All
I have problems with my code in TestNG.
Need to Annotate Parameters to the method.
1) Generation Random Stings
public String RandomName(){
ArrayList<String> alphaNum = new ArrayList<String>();
for (char i = 'A';i<= 'Z';i++){
String s = new String();
s +=i;
alphaNum.add(s);
}
for (char i = 'a';i<= 'z';i++){
String s = new String();
s +=i;
alphaNum.add(s);
}
String[] RandomEnteredField = new String[10];
for (int i = 0; i < RandomEnteredField.length; i++) {
RandomEnteredField[i] = alphaNum.get((int)(Math.random()*alphaNum.size()));
}
String result = "";
for(int i = 0; i < RandomEnteredField.length; i++)
{
result += RandomEnteredField[i];
}
System.out.println(result);
return result;
}
2) In test class I save it like global String
#Test(priority =0)
public void CreateAcount() throws Exception {
objFifthIssue = new TheFifthIssue(driver);
objFifthIssue.ClickOnMyAccount();
String rn = objFifthIssue.RandomName(); // add new argument to EnterRegistrationForm and also 2 below
EmailRandom = objFifthIssue.RandomName();
Password = objFifthIssue.RandomName();
objFifthIssue.EnterRegistrationForm(rn,EmailRandom,Password);
objFifthIssue.VerifyRegistrationDone();
}
3) I would like saved EmailRandom and Password to set in another test class like parameters
#Test(priority =2, dataProvider="LogInOUt")
public void LogoutLogIN(String EmailRandom, String Password) throws Exception {
System.out.println(EmailRandom + Password);
objSixIssue = new SixIssue(driver);
objSixIssue.LogoutLogIN(EmailRandom,Password);
}
4) In DataProvider I try to
#DataProvider(name = "LogInOUt")
public static Object[][] Generation() {
return new Object[] { { EmailRandom }, { Password }};
}
You have an interesting return in your Dataprovider there:
public static Object[][] Generation() {
return new Object[] { { EmailRandom }, { Password }};
}
I assume what you're trying to do here is this:
public static Object[][] Generation() {
return new Object[][] { { EmailRandom }, { Password }};
}
Now it's actually returning the correct datatype. However, this is not the correct way to utilize Selenium DataProviders. (the above code won't work)
DataProviders, as you know, are two-dimensional arrays. This is how you're doing it:
Array 1: {argument 1}
Array 2: {argument 2}
This is how it's supposed to work:
Array 1: {argument 1, argument 2}
Array 2: {argument 1, argument 2}
The first dimension of the array iterates on each time it runs the method. It's two-dimensional so that you can run a different set of arguments with the same method over and over. Does that make sense?
Example: You want to run the method meet(Person, Person) three times. The first time you run it, you want Bob and John to meet. The second time, you want Laura and Sarah to meet. The third time, you want Bob and Sarah to meet. You would use this DataProvider on the meet() method:
public static Object[][] provider() {
return new Object[][] {
{Bob, John},
{Laura, Sarah},
{Bob, Sarah}
};
}
Get it?
So now, if we look at your code, it appears you're only trying to pass one set of arguments with the DataProvider. Since it has to be a two-dimensional array, though, we can just put all the arguments in the first array. Like so:
#DataProvider(name = "LogInOUt")
public static Object[][] Generation() {
return new Object[][] {{ EmailRandom, Password }};
}
Let me know if anything I said didn't make sense :)
I have the following program:
class Books
{
String title;
String author;
}
class BookTestDrive
{
public static void main(String [] args)
{
Books [] myBooks = new Books[3];
int x = 0;
myBooks[0].title = "The Grapes of Java";
myBooks[1].title = "The Java Gatsby";
myBooks[2].title = "The Java Cookbook";
myBooks[0].author = "bob";
myBooks[1].author = "sue";
myBooks[2].author = "ian";
while (x < 3)
{
System.out.print(myBooks[x].title);
System.out.print(" by ");
System.out.println(myBooks[x].author);
x = x + 1;
}
}
}
However, it gives me the following error when I execute it:
Exception in thread "main" java.lang.NullPointerException
at BookTestDrive.main(Books.java:14)
I am new to Java. The code looks legitimate from my C/C++ experience...How to resolve this problem?
The issue is that you have only created the array of books in the following lines -
Books [] myBooks = new Books[3];
You still need to initialize each element in the array to a book object before accessing them.
An example code would look like -
Books [] myBooks = new Books[3];
int x = 0;
myBooks[0] = new Books();
myBooks[0].title = "The Grapes of Java";
You need to do this for all elements in your array.
I second the answer from #AnandSKumar (it is the direct answer to the problem after all), but because it is a matter of beauty, I could not leave without making following few changes:
public class Play {
static public class Book {
final public String title;
final public String author;
public Book(String title,String author) {
this.title = title;
this.author = author;
}
#Override
public String toString() {
return "\""+title+"\" by "+author;
}
}
public static void main(String [] args)
{
Book [] books = new Book[] {
new Book("The Grapes of Java","bob"),
new Book("The Java Gatsby","sue"),
new Book("The Java Cookbook","ian"),
};
for (Book book:books) {
System.out.println(book);
}
}
}
You can initialize in-line the content of your array
If you represent 'a single book' then we should name the class representing it as Book and not Books to avoid confusion.
We can enhance the Book class with an improved toString(), and use that instead.
There is a enhanced for iterator to loop over your array.
Note that the third position book in the array, also ends with a comma, although there is no element following it. This could have been a mistake, but it this case it was a deliberate choice. Makes it easier to copy-paste into next elements without introducing errors, as the Java syntax allows for it.
Because once a book is created, title and author should not change anymore, it might be good to design the Book class to be 'Immutable'. For this reason a constructor was added, and the title and author fields set as final. You could also consider making them private, and provide getters.
I know that there isn't way to access to the links of variables in java (like in &C or &php). But for example I have such task:
public class JustTest {
private int n = 1;
private int x = 10;
public int[] getIntegers() {
return new int[] { n, x };
}
public void filledInteger() {
int[] vals = getIntegers();
System.out.println("Before change");
System.out.println(Arrays.toString(vals));
vals[0] = 2;
vals[1] = 20;
System.out.println("After change");
System.out.println(Arrays.toString(vals));
System.out.println("Values of name & xml");
System.out.println(n);
System.out.println(x);
System.out.println("calling getIntegers");
System.out.println(Arrays.toString(getIntegers()));
}
public static void main(String[] args) {
JustTest t = new JustTest();
t.filledInteger();
}
}
The result is:
Before change
[1, 10]
After change
[2, 20]
Values of name & xml
1
10
calling getIntegers
[1, 10]
So, I want to change values of "n" and "x" fields of the class instance. I can't do this by setting straightly (this->n = 20;), because I may dont know what fields do I have. Only method getIntegers knows.
(No in this code, but for example I have child class with its own fields and in the parent class I have a method filledInteger() which should change specified properties of the child class ( he knows about this properties from the method getIntegers which is abstract in the parent class and implemented in the child class))
Here is simple implementation (without inheritance), using links in php
<?php
class JustTest {
private $n = 1;
private $x = 10;
public function getIntegers() {
return array( &$this->n, &$this->x );
}
public function filledInteger() {
$vals = $this->getIntegers();
echo("Before change" . "<br/>");
echo(print_r($vals, true) . "<br/>");
$vals[0] = 2;
$vals[1] = 20;
echo("After change" . "<br/>");
echo(print_r($vals, true) . "<br/>");
echo("Values of n & x". "<br/>");
echo $this->n , "<br/>";
echo $this->x , "<br/>";
echo("call getIntegers again" . "<br/>");
echo(print_r($this->getIntegers(), true) . "<br/>");
}
}
$t = new JustTest();
$t->filledInteger();
?>
The result is:
Before change
Array ( [0] => 1 [1] => 10 )
After change
Array ( [0] => 2 [1] => 20 )
Values of n & x
2
20
call getIntegers again
Array ( [0] => 2 [1] => 20 )
That is what I exactly need. Im just curious how do I implement this in java
Hope you understood.
Next example:
public abstract class ParentTest {
abstract int[] getIntegers();
public void fillIntegers(int[] newIntegers) {
int[] integersOfChild = getIntegers();
for (int i = 0; i < integersOfChild.length; i++) {
integersOfChild[i] = newIntegers[i];
}
}
}
public class ChildTest extends ParentTest {
private int x;
private int y;
#Override
int[] getIntegers() {
return new int[] {x, y};
}
}
public class UseTest {
void main() {
List<ParentTest> list;
for (ParentTest item : list) {
item.fillIntegers(myItegers);
}
}
}
This is what I need. I have a list of ParentTest instances (it may be ChildTest, or ChildTest2, or ChildTest3; but they all children of a ParentTest) and I need to fill all fields with my integer values, but I dont know if items in the list instances of a ChildTest, or ChildTest2, or ChildTest3 class
How do I implement this in Java?
With great pain via the Reflection API. If you want to write code like this, the best idea is to use another language.
Consider programming in Groovy instead. You can use array syntax to directly access class members by name: t["n"] = 2; This works with legacy Java code, so there is no need to modify TestClass to support this usage.
The concept you are talking about is called pass by reference. Java has for the most part abandoned it - it creates too many side-effects, like the one you are seeing here.
The issue is that while unfortunately you can't do this here, it actually prevents a huge number of unintentional bugs being released.
What about something like that:
public final class JustTest {
private final Map<String, Object> fields;
public void filledInteger() {
System.out.println("Before change\n" + this.fields);
fields.put("N", 2);
fields.put("X", 20);
System.out.println("After change\n" + this.fields);
System.out.println("Values of name & xml\n" + fields.get("N")
+ "\n" + fields.get("X"));
}
private JustTest() {
this.fields = Maps.newHashMap(); // guava
fields.put("N", 1);
fields.put("X", 10);
}
public static void main(String[] args) {
final JustTest t = new JustTest();
t.filledInteger();
}
}
You can't do individual fields without reflection, but you can change the contents of collections. Note that this is not really intended behavior, but rather something you have to be careful of when using collections.
This outputs 5 3 2 4 2 4
public class Test
{
public Vector<Integer> args = new Vector<Integer>();
public void fillArgs()
{
args.add(5);
args.add(3);
}
public Vector<Integer> getArgs()
{
return args;
}
public static void main(String args[])
{
Test s = new Test();
s.fillArgs();
Vector<Integer> temp = s.getArgs();
for (Integer i : temp)
System.out.println(i);
temp.setElementAt(2, 0);
temp.setElementAt(4, 1);
for (Integer i : temp)
System.out.println(i);
for (Integer i : s.getArgs())
System.out.println(i);
}
}
Your php example does not return an array of ints, but rather an array of int pointers. This is NOT something you can do in Java, in fact, this is NOT something you want to do in Java. Give a use case, and there is likely a better way to solve the problem you have.
If you want to return an object that others can affect and that are contained as member variables, do that. An ArrayList, HashMap, etc... there are plenty of things that can fit your needs. If you are given someone elses class and you must stick your nose in their code, you can get around their private declaration doing the following:
public void setN(JustTest j, int n) {
//You would handle some exceptions here also
Field f = JustTest.class.getDeclaredField("n");
f.setInt(j, n);
}
I have four different classes classA, classB, classC and classD. All the four classes have the same static method search() which takes two string parameters. If i want to invoke static method search in four different classes from main class at once. How can I do that. For now my code is as follows for main class. I need to execute the same thing for other 3 classes also. How can i do that and display the results of other 3 in the same way as for classA. The way search is done in 4 classes r different but they should give the same result.
Main() {
Object[] zy;
for (String pattern : Read.arrayList) {
List<Integer> results = ClassA.findAll(pattern, dataToSearch);
zy = results.toArray();
for (int i = 0; i < zy.length; i++) {
System.out.println(" Pattern searched " + pattern + " match is found at index : "+ results);
}
}
if (zy.length == 0) {
System.out.println("Nothing matched");
}
}
I strongly recommend you change this to non-static methods. Look how easy and nice is when you will seperate an interface:
public interface Common {
List<Integer> findAll(String pattern, String dataToSearch);
}
public class A implements Common ...
public class B implements Common ...
public class C implements Common ...
public class D implements Common ...
// in main:
List<Common> allYourClasses = new ArrayList<Common>();
allYourClasses.add(new A());
allYourClasses.add(new B());
allYourClasses.add(new C());
allYourClasses.add(new D());
List<Integer> result = new ArrayList<Integer>();
for (Common c : allYourClasses) {
result.addAll(c.findAll(pattern, dataToSearch));
}
1 - You should NOT do this. Avoid static methods. One of the reason being they can not be called without the exact class. A group of classes that implement a simple interfaces will work faster, safer and better in every way
2 - You can (but you shouldn't) do something like this:
for (Class<?> clazz : new Class[] { ClassA.class, ClassB.class,
ClassC.class }) {
Object[] zy = null;
String dataToSearch = "";
String[] arrayList = { "a" };
for (String pattern : arrayList) {
List<Integer> results = findAllForClass(clazz, pattern,
dataToSearch);
zy = results.toArray();
for (int i = 0; i < zy.length; i++) {
System.out.println(" Pattern searched " + pattern
+ " match is found at index : " + results);
}
}
if (zy.length == 0) {
System.out.println("Nothing matched");
}
}
#SuppressWarnings("unchecked")
public static List<Integer> findAllForClass(Class<?> clazz, String pattern,
String dataToSearch) {
List<Integer> list = null;
try {
list = (List<Integer>) clazz.getDeclaredMethod("findAll", String.class,
String.class).invoke(null, pattern, dataToSearch);
} catch (Exception e) {
list = Collections.emptyList();
}
return list;
}
You see the #supresswarning and the try/catch? well, this is a hint: is telling you you this code is at least suspicious. It is in fact unsafe, non well performant, and is a stupid workaround.
(But we all did something like that once in our lives)
I can't really figure out why would anyone do that.
That said, you could have a method taking a Class as a parameter and calling the method explicitly by name (getMethod.../invoke()).
That puts you back in non static world and you can iterate over the classes you want to invoke. (But again, why use statics in the first place?)
Pseudo untested code:
public void invokeStatic(Class clazz, String method, Class<?> paramsTypes[], Object[] params) {
Method method = clazz.getMethod(method, paramsType);
method.invoke(params);
}
If you want to group all of the results together, just keep adding results to your list:
List<Integer> results = ClassA.findAll(pattern, dataToSearch);
results.addAll(ClassB.findAll(pattern, dataToSearch));
// etc.