Ho impostato una classe con un paio di test e invece di utilizzare @Before
vorrei avere un metodo di installazione che viene eseguito solo una volta prima di tutti i test. È possibile con Junit 4.8?
Ho impostato una classe con un paio di test e invece di utilizzare @Before
vorrei avere un metodo di installazione che viene eseguito solo una volta prima di tutti i test. È possibile con Junit 4.8?
Risposte:
Anche se sono d'accordo con @assylias che l'utilizzo @BeforeClass
è una soluzione classica non è sempre conveniente. Il metodo annotato con @BeforeClass
deve essere statico. È molto scomodo per alcuni test che richiedono un'istanza di test case. Ad esempio, test basati sulla primavera che utilizzano @Autowired
per lavorare con i servizi definiti nel contesto della primavera.
In questo caso utilizzo personalmente il setUp()
metodo regolare annotato con @Before
annotazione e gestisco il mio flag personalizzato static
(!) boolean
:
private static boolean setUpIsDone = false;
.....
@Before
public void setUp() {
if (setUpIsDone) {
return;
}
// do the setup
setUpIsDone = true;
}
setUp()
metodo è in una superclasse - ho pubblicato una risposta di seguito tentando di risolverlo.
Puoi usare l' BeforeClass
annotazione :
@BeforeClass
public static void setUpClass() {
//executed only once, before the first test
}
TheClassYouWant.class
posto della tua chiamata getClass ()? Questo è vero e proprio Java: String.class.getName()
.
JUnit 5 ora ha un'annotazione @BeforeAll:
Indica che il metodo annotato deve essere eseguito prima di tutti i metodi @Test nella classe corrente o nella gerarchia di classi; analogo a @BeforeClass di JUnit 4. Tali metodi devono essere statici.
Le annotazioni del ciclo di vita di JUnit 5 sembrano aver finalmente capito bene! Puoi indovinare quali annotazioni sono disponibili senza nemmeno guardare (ad esempio @BeforeEach @AfterAll)
@BeforeClass
, deve essere static
. La soluzione di IMO @ AlexR è migliore.
Quando si setUp()
trova in una superclasse della classe di test (ad esempio AbstractTestBase
sotto), la risposta accettata può essere modificata come segue:
public abstract class AbstractTestBase {
private static Class<? extends AbstractTestBase> testClass;
.....
public void setUp() {
if (this.getClass().equals(testClass)) {
return;
}
// do the setup - once per concrete test class
.....
testClass = this.getClass();
}
}
Questo dovrebbe funzionare per un singolo setUp()
metodo non statico , ma non sono in grado di produrre un equivalente tearDown()
senza perdersi in un mondo di riflessioni complesse ... Bounty punta a chiunque possa!
Modifica: ho appena scoperto durante il debug che la classe viene istanziata anche prima di ogni test. Immagino che l'annotazione @BeforeClass sia la migliore qui.
Puoi anche configurarlo sul costruttore, la classe di test è una classe dopotutto. Non sono sicuro che sia una cattiva pratica perché quasi tutti gli altri metodi sono annotati, ma funziona. Potresti creare un costruttore come quello:
public UT () {
// initialize once here
}
@Test
// Some test here...
Il ctor verrà chiamato prima dei test perché non sono statici.
Prova questa soluzione: https://stackoverflow.com/a/46274919/907576 :
con @BeforeAllMethods
/ @AfterAllMethods
annotation è possibile eseguire qualsiasi metodo nella classe Test in un contesto di istanza, in cui sono disponibili tutti i valori inseriti.
La mia soluzione sporca è:
public class TestCaseExtended extends TestCase {
private boolean isInitialized = false;
private int serId;
@Override
public void setUp() throws Exception {
super.setUp();
if(!isInitialized) {
loadSaveNewSerId();
emptyTestResultsDirectory();
isInitialized = true;
}
}
...
}
Lo uso come base per tutti i miei casi di test.
Se non vuoi forzare una dichiarazione di una variabile che è impostata e controllata su ogni subtest, aggiungerlo a un SuperTest potrebbe fare:
public abstract class SuperTest {
private static final ConcurrentHashMap<Class, Boolean> INITIALIZED = new ConcurrentHashMap<>();
protected final boolean initialized() {
final boolean[] absent = {false};
INITIALIZED.computeIfAbsent(this.getClass(), (klass)-> {
return absent[0] = true;
});
return !absent[0];
}
}
public class SubTest extends SuperTest {
@Before
public void before() {
if ( super.initialized() ) return;
... magic ...
}
}
Ho risolto questo problema in questo modo:
Aggiungi alla tua classe astratta di base (intendo la classe astratta in cui inizializzi il tuo driver nel metodo setUpDriver () ) questa parte di codice:
private static boolean started = false;
static{
if (!started) {
started = true;
try {
setUpDriver(); //method where you initialize your driver
} catch (MalformedURLException e) {
}
}
}
E ora, se le classi di test si estendono dalla classe astratta Base -> il metodo setUpDriver () verrà eseguito prima del primo @Test solo UNA volta per esecuzione.
Usa il metodo @PostConstruct di Spring per eseguire tutto il lavoro di inizializzazione e questo metodo viene eseguito prima che venga eseguito uno qualsiasi dei @Test