This question already has answers here:
How to test randomness (case in point - Shuffling)
(11 answers)
Closed 8 years ago.
I have written a method to shuffle a String array
So the task is to implement WhiteElephant concept for a given string array of list of names.Should generate assignments to match the original elements.
I have written method to pick a random number and used a map to store the values so that each value will have a different index. But this prints out only 5 values. and i am confused now.
public static String[] generateAssignments(final String[] participants) {
Random r = new Random();
int size = participants.length;
HashMap val = new HashMap();
int change = 0;
String[] assignments = new String[6];
System.out.println("Using arrays");
for(int i=0; i<size;i++){
for(int j =0; j<size; j++){
change = r.nextInt(size);
if(val.containsValue(change) || change==i){
continue;
}
else val.put(i, change);
assignments[i] = participants[change];
System.out.println(assignments[i]);
break;
}
}
return assignments;
}
I appreciate your inputs.
Thanks,
Lucky
If your shuffle method is random (or pseudorandom) it will be near impossible to unit test since the output is non deterministic. If you allow for seeding a random number generator then you could ensure the output is consistent given the same seeds, though this doesn't show randomness.
You could also run the shuffle method a large number of times and check that each card shows up at each index an approixmately equal number of times. Over a large enough number of simulations this should help illustrate randomness.
FYI - There are some logical errors in both your shuffle() code and the test. I won't address those here; hopefully having a good test will allow you to figure out the problems!
Writing tests around Random data is hard.
The best option is to pass in an instance of Random to your shuffle() method or it's containing class. Then in test usages, you can pass in an instance of Random which has been seeded with a known value. Given that the Random code will behave the same every time and you control the input array, your test will be deterministic; you can confidently assert on each object in the sorted collection.
The only downside of this approach is that you won't have a test preventing you from re-writing your shuffle() method to simply re-order the elements every time into this specified order. But that might be over-thinking it; usually we can trust our future selves.
An alternative approach is to assume that in a Random world, given enough time, every data possibility will be realized.
I used this approach when testing a 6-sided die's roll() method. I needed to ensure that getting all values from 1-6 was possible. I didn't want to complicate the method signature or the Die constructor to take in an instance of Random. I also didn't feel confident in a test that used a known seed and simply always asserted 3 (i.e.).
Instead, I made the assumption that given enough rolls, all values from 1-6 would eventually be rolled. I wrote a test that infinitely called roll until all values from 1-6 had been returned. Then I added a timeout to the test so that it would fail after 1 second if the above condition hadn't been met.
#Test(timeout = 1000)
public void roll_shouldEventuallyReturnAllNumbersBetweenOneAndSixInclusively() {
Die die = new Die();
Set<Integer> rolledValues = new HashSet<Integer>();
int totalOfUniqueRolls = 0;
while (rolledValues.size() < Die.NUM_SIDES) {
if (rolledValues.add(die.roll())) {
totalOfUniqueRolls += die.getFaceValue();
}
}
assertEquals(summation(1, Die.NUM_SIDES), totalOfUniqueRolls);
}
Worst case scenario it fails after 1 second (which hasn't happened yet) but it usually passes in about 20 milliseconds.
The test must be reproducible: it is not useful if it depends on something random.
I suggest you to use mocking so the CUT (code under test) don't use the real Random class instantiated in production, but a different class written by you with a predictable behavior, giving you the possibility to make some significant assertions on two or three items.
It appears your shuffle() method will always return the same result. So given a input test array of however many elements in your test, just specify the exact output array you'd expect.
It looks like you are trying to write a very general test. Instead, your tests should be very specific: given a specific input A then you expect a specific output B.
Related
The scenario is like i will fetch four data from open api end points from a json array for the first threenter code heree output. Then i kept the data in four arraylist, account no, com amount, revenue amount, mark up realized amount. Till this it works fine. Now i have to take the first index data from each of the list and use it in a test method. In this whay i would take the secound index, third indexx data from array list and use it in the sme test method. The test method will go the ui and vaidate. I have right now used a loop which executes this test method three times by taking data three times from the arraylist. Is there a different way where i can avoid the loop in test method and the test method will execute three times by taking the each index value from the arraylist.
#Test(dependsOnMethods = "getTransactionRecordDetailsForSpecificAccountNumberByDateRange")
public void verifyTransactionDetailsFromOpenAPIOnSFObject() throws InterruptedException, AWTException {enter code here
for (int i = 0; i < 3; i++) {
launchApp();
homepage = new HomePage();
companyaccountpage = new CompanyAccountPage();
homepage.navigateToCompanyAccountDetailsPage(li_AcctNo.get(i));
companyaccountpage.navigateToTransactionTableDetails();
Assert.assertEquals(companyaccountpage.getValueOfTotalComissionAmountFromTransactionTable(actual_tsDate),
li_comAmt.get(i));
Assert.assertEquals(companyaccountpage.getValueOfTotalMarkUpRealizedAmountTransactionTable(actual_tsDate),
li_markupAmt.get(i));
Assert.assertEquals(companyaccountpage.getValueOfTotalRevenueAmountFromTransactionTable(actual_tsDate),
li_revenueAmt.get(i));`enter code here`
fd.quit();
Perhaps three different test cases would be another way to do things logically too since you're testing for different details. If you're worried about code duplication, then you can make a separate function for the loop logic.
I am trying to write a program containing 3 String ArrayLists, where 1 item may be included in all 3 ArrayLists. However, the output must insure that the randomly selected items are all different. As I work through this issue, I am just using numbers so it will be easier to catch. I have been trying to solve this problem for a few days now, and figure there must be something I am overlooking. Here is the code for the method that must have the fault:
private void generateThree() {
// Find the maximum number the random can be.
index = thirdNumberArray.size();
// Initiate the random function.
Random rand = new Random();
// Generate a random number from 1 to the maximum.
randomInt = rand.nextInt(index);
// Access the item in the ArrayList using the random number as the index.
thirdDrawn = thirdNumberArray.get(randomInt);
// Check that the number is different than any previously set numbers.
while ((thirdDrawn.equals(secondDrawn)) || (thirdDrawn.equals(firstDrawn))) {
randomInt = rand.nextInt(index);
thirdDrawn = thirdNumberArray.get(randomInt);
}
// Set the output.
thirdNumberLabel.setText((thirdDrawn));
// Reset the index.
index = 0;
}
So far, the IF statement I use to check the secondDrawn against the firstDrawn has worked perfectly. But the above code still allows the thirdDrawn to display a duplicate of both the firstDrawn and secondDrawn. I know this problem has to be in my loop logic, but I just can't grasp what it is. I have tried multiple different IF statements, but they didn't solve the whole problem. Can anyone give me some feedback or corrections? Thanks in advance.
Any time you generate a number you want to draw, add it to a HashSet<String>. Then, have your if statement conditional check !myHashset.contains(thirdDrawn).
I want to declare integers, while the program is running.
I run the program, and then I give it via System.in.println an integer and repeat this as long as I want.
I want the program to give those integers a name of a certain type for, for example a(i) or a[i], dunno, (it should be handy) and then a(i) represents the the i'th integer I gave the program.
My idea is then that I can use those elements by their name just like, if I had declared them in the first place.
For example add two integers together.
For example I defined a method add+, which waits for 2 integer and then adds them. For example I write:
add
a(2)
a(47)
(then I would get here the result.)
I don't think implementing the add function is difficult. However I don't know, how to let the program count the number of inputs or how to let it declare and use variables.
First: Welcome to programming java; it will be a long road.
Here are some hints:
Use a List<Integer> to hold the sequence of numbers entered by the user.
Actually instanciate a concreate List class, for example LinkedList<Integer>'. If you need to access the elements by index, use anArrayList`.\
Each time the user enters a number, create a new Integer and userList.add(newInteger);
Simple sample
List<Integer> userList = new LinkedList<Integer>();
for (index = 0; index < 9; ++index)
{
Integer newInteger = new Integer(index);
userList.add(newInteger);
}
for (Integer current : userList)
{
System.out.println(current);
}
Yeah, I am following the conversation.
I am just a bit frustrated, because I can't really write any interesting or practical java programs (yet), because my knowledge isn't that big yet.
First I tried to find out, if there was a way to add elements to array, because arrays seemed to me very useful, because each element of an array already has an address. I googled, and it seems that is not possible.
I might be able to use the idea with the list, but it seems to be that the length of the list has to have a limit and actually I wanted to avoid that.
I am trying to get my app to determine the best solution for grouping 20 golfers into foursomes.
I have data that shows when a golfer played, what date and the others in the group.
I would like the groups made up of golfer who haven't played together, or when everyone has played together, the longest amount of time that they played together. In other words, I want groups made up of players who haven't played together in a while as opposed to last time out.
Creating a permutation list of 20! to determine the lowest combinations didn't work well.
Is there another solution that I am not thinking of?
#Salix-alba's answer is spot on to get you started. Basically, you need a way to figure out how much time has already been spent together by members of your golfing group. I'll assume for illustration that you have a method to determine how much time two golfers have spent together. The algorithm can then be summed up as:
Compute total time spent together of every group of 4 golfers (see Salix-alba's answer), storing the results in an ordered fashion.
Pick the group of 4 golfers with the least time together as your first group.
Continue to pick groups from your ordered list of possible groups such that no member of the next group picked is a member of any prior group picked
Halt when all golfers have a group, which will always happen before you run out of possible combinations.
By way of quick, not promised to compile example (I wrote it in the answer window directly):
Let's assume you have a method time(a,b) where a and b are the golfer identities, and the result is how much time the two golfers have spent together.
Let's also that assume that we will use a TreeMap> to keep track of "weights" associated with groups, in a sorted manner.
Now, let's construct the weights of our groups using the above assumptions:
TreeMap<Integer,Collection<Integer>> options = new TreeMap<Integer, Collection<Integer>>();
for(int i=0;i<17;++i) {
for(int j=i+1;j<18;++j) {
for(int k=j+1;k<19;++k) {
for(int l=k+1;l<20;++l) {
Integer timeTogether = time(i,j) + time(i,k) + time(i,l) + time(j,k) + time(j,l)+time(k,l);
Collection<Integer> group = new HashSet<Integer>();
group.add(i);
group.add(j);
group.add(k);
group.add(l);
options.put(timeTogether, group);
}
}
}
}
Collection<Integer> golferLeft = new HashSet<Integer>(); // to quickly determine if we should consider a group.
for(int a=0; a < maxGolfers, a++) {
golferLeft.add(a);
}
Collection<Collection<Integer>> finalPicks = new ArrayList<Collection<Integer>>();
do{
Map.Entry<Integer, Collection<Integer>> least = options.pollFirstEntry();
if (least != null && golferLeft.containsAll(least.getValue()) {
finalPicks.add(least.getValue());
golferLeft.removeAll(least.getValue());
}
}while (golferLeft.size() > 0 && least != null);
And at the end of the final loop, finalPicks will have a number of collections, with each collection representing a play-group.
Obviously, you can tweak the weight function to get different results -- say you would rather be concerned with minimizing the time since members of the group played together. In that case, instead of using play time, sum up time since last game for each member of the group with some arbitrarily large but reasonable value to indicate if they have never played, and instead of finding the least group, find the largest. And so on.
I hope this has been a helpful primer!
There should be 20 C 4 possible groupings which is 4845. It should be possible to generate these combinations quite easily with four nested for loops.
int count = 0;
for(int i=0;i<17;++i) {
for(int j=i+1;j<18;++j) {
for(int k=j+1;k<19;++k) {
for(int l=k+1;l<20;++l) {
System.out.println(""+i+"\t"+j+"\t"+k+"\t"+l);
++count;
}
}
}
}
System.out.println("Count "+count);
You can quickly loop through all of these and use some objective function to workout which is the most optimal grouping. Your problem definition is a little fuzzy so I'm not sure how tell which is the best combination.
Thats just the number of way picking four golfers out of 20, you really need 5 group of 4 which I think is 20C4 * 16C4 * 12C4 * 8C4 which is 305,540,235,000. This is still in the realm of exhaustive computation though you might need to wait a few minutes.
Another approach might be a probabilistic approach. Just pick the groups at random, rejecting illegal combinations and those which don't meet your criteria. Keep picking random groups until you have found which is good enough.
I'm working on training myself in a very rigid Test Driven Development JUnit atmosphere. I'm trying to find out what the best method for testing FOR randomness would be in such an atmosphere. For example, I'm working on implementing a randomized queue array that queues and item and immediately switches that item with an item with index 0-(n-1) on the array (thus simulating a random item coming off the queue when it is dequeued). Here's some example code form my enqueue method:
int randIndex = StdRandom.uniform(size); // generate random index to swap with last item
Item tmp = randArray[randIndex];
randArray[size] = item;
randArray[randIndex] = randArray[size]; //perform swap to create a random item for dequeue
randArray[size] = tmp;
size++;
I want to run a few tests to make sure that my enqueue method is actually randomly switching the queued variable with some other index in the array. Normally I'd just throw some code in the Main() method that iterates through a bunch of enqueue() calls and prints the results, then I'd check to make sure it "felt" random.
But, like I said, I want to do this in a very rigid unit testing framework. It seems like JUnit pretty much exclusively uses assert statements, but I'm not sure what I should assert against what, unless I just run some Monte Carlo type thing and check the average against a certain epsilon, but that seems a little much for testing such a simple method.
You can split the test in two parts.
1) You test that by a given sequecne of pseudo random numbers, your queing works as expected. For that define any arbitray fixed number of int values: e.g "5,2,100,3".
Then test with asser that the enque, deque delivers that expected element.
2) Test the Random() class of java: You, most likely should omit that test, because Random() is well implemented.
Otherwise for 2) you have it using Chi-Square Random Number Test, and that that that thi sstatistic is within soem epsilon as you stated. But this woul dbe an overkill, so stay with point 1)
I'm not sure what you are really heading for but I read it like testing the random number generator itself (cause your switching is .. quite straight forward).
If you use java SecureRandom, you should be on a quite good side regarding the entropy, see
SecureRandom. If you doubt that, use some entropy checkers or just a sequence of real random from some source in the internet like here