I am new to unit testing and when reading about it I am getting confused about how to do it.
I have this code which shuffles a word entered:
public static void shuffle(String word) {
// Store string into array
ArrayList<Character> wordShuffled = new ArrayList<Character>();
// loop the index of the string
for (i开发者_如何学JAVAnt i = 0; i < wordE.length(); i++) {
wordShuffled.add(word.charAt(i));// add the word
}
Collections.shuffle(wordShuffled);// shuffle the word
How can I write unit tests for the code above. Thanks
An easy check would be to create a hashmap of character vs frequency for the original word.
For ex. if your word is "Doppelganger", the map would be
D->1
o->1
p->2
e->2
l->1
g->2
a->1
n->1
r->1
Create a similar map for the shuffled word. The two hashmaps should be equal.
This, however, will only check that the shuffled word contains the same letters as the original word. You should also check that the word is actually shuffled by checking for String equality and running the shuffle multiple times as @Shengyuan has pointed out.
The obvious Pass test is:
Arrange: create a known word.
Act: call shuffle.
Assert: check result is a permutation of original word.
Then look for failure points or boundary cases for further tests.
A couple of problems that make this piece of code hard to test are:
- Your function shuffle is declared static
- The function calls Collections.shuffle, making it really hard to mock
Here are some suggestions as to how you could test this method, albeit they would require some changes to your design:
public class WordUtil {
public void shuffle(String word) {
// Store string into array
// -> It is better to code to the interface, eg, List, Set, Map
// than to the implementation, eg. ArrayList, LinkedList, HashMap, etc.
List<Character> wordShuffled = new ArrayList<Character>();
// loop the index of the string
for (int i = 0; i < wordE.length(); i++) {
wordShuffled.add(word.charAt(i));// add the word
}
Collections.shuffle(wordShuffled);// shuffle the word
}
// we are making this method visible only for testing purposes but
// shouldn't be regarded as public API
void shuffle(Collection c) {
Collections.shuffle(c);
}
}
public class WordUtilTest {
private boolean shuffleForCollectionWasCalled;
private Collection collectionForShuffle;
public void testShuffle() throws Exception {
WordUtil util = new WordUtil_ForTest();
String word = "some word";
util.shuffle(word);
assertTrue(shuffleForCollectionWasCalled);
List<Character> expected = new ArrayList<Character>();
for (int i = 0; i < word.length; i++) {
expected.add(word.charAt(i);
}
assertEquals(expected, collectionForShuffle);
}
private static class WordUtil_ForTest extends WordUtil {
@Override
void shuffle(Collection c) {
shuffleForCollectionWasCalled = true;
collectionForShuffle = c;
}
}
}
While this might seem a bit convoluted, we need to introduce the void shuffle(Collection c)
because it allows us to control the behavior of Collections.shuffle
making it deterministic, and the implementation we have in WordUtil_ForTest
is trivial because we are not testing how Collections.shuffle
does its work (this is supposed to be well tested in the JDK) we just care that we send the right parameters to it.
You can extend this test by adding conditions to handle null inputs and other edge cases.
Compare results of shuffle()
twice, assertFail()
if results are same.
精彩评论