Rozszerzając odpowiedź Davida, z którą całkowicie się zgadzam, powinieneś stworzyć opakowanie dla Random. Wcześniej napisałem prawie taką samą odpowiedź w podobnym pytaniu, więc oto „wersja notatek Cliffa”.
Co powinieneś zrobić, to najpierw utworzyć opakowanie jako interfejs (lub klasę abstrakcyjną):
public interface IRandomWrapper {
int getInt();
}
Konkretna klasa do tego wyglądałaby tak:
public RandomWrapper implements IRandomWrapper {
private Random random;
public RandomWrapper() {
random = new Random();
}
public int getInt() {
return random.nextInt(10);
}
}
Powiedz, że twoja klasa jest następująca:
class MyClass {
public void doSomething() {
int i=new Random().nextInt(10)
switch(i)
{
//11 case statements
}
}
}
Aby poprawnie korzystać z IRandomWrapper, musisz zmodyfikować swoją klasę, aby przyjmowała ją jako element członkowski (przez konstruktor lub program ustawiający):
public class MyClass {
private IRandomWrapper random = new RandomWrapper(); // default implementation
public setRandomWrapper(IRandomWrapper random) {
this.random = random;
}
public void doSomething() {
int i = random.getInt();
switch(i)
{
//11 case statements
}
}
}
Możesz teraz przetestować zachowanie swojej klasy za pomocą opakowania, wyśmiewając opakowanie. Możesz to zrobić za pomocą fałszywego frameworka, ale jest to również łatwe do zrobienia samemu:
public class MockedRandomWrapper implements IRandomWrapper {
private int theInt;
public MockedRandomWrapper(int theInt) {
this.theInt = theInt;
}
public int getInt() {
return theInt;
}
}
Ponieważ twoja klasa oczekuje czegoś, co wygląda jak IRandomWrapper
wy, możesz teraz użyć kpiny, aby wymusić zachowanie w teście. Oto kilka przykładów testów JUnit:
@Test
public void testFirstSwitchStatement() {
MyClass mc = new MyClass();
IRandomWrapper random = new MockedRandomWrapper(0);
mc.setRandomWrapper(random);
mc.doSomething();
// verify the behaviour for when random spits out zero
}
@Test
public void testFirstSwitchStatement() {
MyClass mc = new MyClass();
IRandomWrapper random = new MockedRandomWrapper(1);
mc.setRandomWrapper(random);
mc.doSomething();
// verify the behaviour for when random spits out one
}
Mam nadzieję że to pomoże.
Możesz (należy) owinąć losowy kod generujący w klasę lub metodę, a następnie wyśmiać / przesłonić go podczas testów, aby ustawić żądaną wartość, aby testy były przewidywalne.
źródło
Masz określony zakres (0–10) i określoną ziarnistość (liczby całkowite). Więc podczas testowania nie testujesz liczb losowych. Testujesz w pętli, która trafia kolejno do każdego przypadku. Radziłbym przekazać liczbę losową do podfunkcji zawierającej instrukcję case, która pozwala tylko przetestować podfunkcję.
źródło
Możesz użyć biblioteki PowerMock, aby wyśmiewać klasę Random i wprowadzić jej metodę nextInt (), aby zwrócić oczekiwaną wartość. Nie musisz zmieniać oryginalnego kodu, jeśli nie chcesz.
Używam PowerMockito i właśnie przetestowałem metodę podobną do twojej. W przypadku kodu, który opublikowałeś, test JUnit powinien wyglądać mniej więcej tak:
Możesz także pominąć wywołanie nextInt (int), aby otrzymać dowolny parametr, na wypadek, gdybyś chciał dodać więcej przypadków na przełączniku:
Ładne, prawda? :)
źródło
Użyj QuickCheck ! Właśnie zacząłem grać z tym niedawno i jest niesamowity. Jak większość fajnych pomysłów, pochodzi od Haskella, ale podstawową ideą jest to, że zamiast dawać testowi gotowe skrzynki testowe, pozwalasz generatorowi liczb losowych zbudować je dla ciebie. W ten sposób zamiast 4-6 przypadków, które prawdopodobnie wymyślisz w xUnit, możesz poprosić komputer o wypróbowanie setek lub tysięcy danych wejściowych i sprawdzenie, które nie są zgodne z ustawionymi regułami.
Również QuickCheck, gdy znajdzie przypadek nieudany, spróbuje go uprościć, aby mógł znaleźć najprostszy możliwy przypadek, który się nie powiedzie. (I oczywiście, gdy znajdziesz niesprawny przypadek, możesz go również wbudować w test xUnit)
Wydaje się, że istnieją co najmniej dwie wersje Java, więc ta część nie powinna stanowić problemu.
źródło