Voglio coprire una logica, che crea file con test unitari. È possibile prendere in giro la classe File e evitare la creazione effettiva di file?È possibile utilizzare PowerMock per simulare la creazione di nuovi file?
risposta
Mock the constructor, come in questo esempio di codice. Non dimenticare mettere la classe che richiamerà il "nuovo file (...)" nella @PrepareForTest
package hello.easymock.constructor;
import java.io.File;
import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest({File.class})
public class ConstructorExampleTest {
@Test
public void testMockFile() throws Exception {
// first, create a mock for File
final File fileMock = EasyMock.createMock(File.class);
EasyMock.expect(fileMock.getAbsolutePath()).andReturn("/my/fake/file/path");
EasyMock.replay(fileMock);
// then return the mocked object if the constructor is invoked
Class<?>[] parameterTypes = new Class[] { String.class };
PowerMock.expectNew(File.class, parameterTypes , EasyMock.isA(String.class)).andReturn(fileMock);
PowerMock.replay(File.class);
// try constructing a real File and check if the mock kicked in
final String mockedFilePath = new File("/real/path/for/file").getAbsolutePath();
Assert.assertEquals("/my/fake/file/path", mockedFilePath);
}
}
Non sono sicuro che sia possibile, ma ho avuto tale esigenza e l'ho risolto creando un'interfaccia FileService
. Quindi, invece di creare/accedere direttamente ai file, aggiungi un'astrazione. Quindi puoi facilmente prendere in giro questa interfaccia nei tuoi test.
Per esempio:
public interface FileService {
InputStream openFile(String path);
OutputStream createFile(String path);
}
Poi nella classe utilizzando questo:
public class MyClass {
private FileService fileService;
public MyClass(FileService fileService) {
this.fileService = fileService;
}
public void doSomething() {
// Instead of creating file, use file service
OutputStream out = fileService.createFile(myFileName);
}
}
E nel tuo test
@Test
public void testOperationThatCreatesFile() {
MyClass myClass = new MyClass(mockFileService);
// Do your tests
}
In questo modo, si può anche prendere in giro senza alcuna finta librerie.
corretto. Quando non riesci a deridere, avvolgilo in un'astrazione (interfaccia) e poi prendilo in giro. –
Ma poi stai cambiando il codice reale per aiutare i test, è buono e possibile evitarlo con EasyMock/PowerMock – cahen
@CarlosHenriqueRodriguez Sì, lo sei. E questa è una buona cosa. Scrivere codice che è testabile (spesso) riduce l'accoppiamento nel codice. Dovresti considerare il codice di prova come parte della tua architettura. – NilsH
provare PowerMockito
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
@PrepareForTest(YourUtilityClassWhereFileIsCreated.class)
public class TestClass {
@Test
public void myTestMethod() {
File myFile = PowerMockito.mock(File.class);
PowerMockito.whenNew(File.class).withAnyArguments().thenReturn(myFile);
Mockito.when(myFile.createNewFile()).thenReturn(true);
}
}
Questa è una buona domanda. Non merita di essere downvoted. –
Hai provato a usare PowerMock? PowerMock simula nuove creazioni di oggetti all'interno del metodo, quindi dovrebbe funzionare. –