[JAVA] Testen Sie eine Klasse, die einen Kontext empfängt und Dateien liest und schreibt

Ich bin süchtig danach, Testcode für Klassen zu schreiben, die "Context" im Konstruktor empfangen und "Context.openFileInput" und "Context.openFileOutput" verwenden, also schreibe ich ihn auf.

Zu testende Klasse

BooleanRepository.java


public class BooleanRepository {
    static final String FILE_NAME = "BOOLEAN.txt";

    @NonNull private final Context context;

    public BooleanRepository(@NonNull Context context) { this.context = context; }

    public boolean load() throws IOException {
        try (final InputStream is = context.openFileInput(FILE_NAME);
             final InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
             final BufferedReader reader = new BufferedReader(isr)) {
            return Boolean.valueOf(reader.readLine());
        }
    }

    public void save(boolean bool) throws IOException {
        try (final OutputStream os = context.openFileOutput(FILE_NAME, Context.MODE_PRIVATE);
             final OutputStreamWriter osw = new OutputStreamWriter(os, StandardCharsets.UTF_8);
             final PrintWriter writer = new PrintWriter(osw)) {
            writer.append(bool);
        }
    }
}

Schlussfolgerung Verwendung * Robolectric *

Mit * Robolectric * können auch Android-abhängige Tests auf der JVM ausgeführt werden.

build.gradle


android {
    compileSdkVersion 28
    ...
    testOptions {
        unitTests {
            includeAndroidResources = true
        }
    }
}

dependencies {
    testImplementation 'androidx.test:core:1.2.0'
    testImplementation 'com.google.truth:truth:0.45'
}

BooleanRepositorySpec.java


@RunWith(RobolectricTestRunner.class)
public class MemoRepositorySpec {
    private static final boolean INPUT_BOOL = true;
    private static final String INPUT_STRING = String.valueOf(INPUT_BOOL);

    private BooleanRepository booleanRepository;
    private Context context;

    @Before
    public void setUp() {
        this.context = ApplicationProvider.getApplicationContext();
        this.booleanRepository = new BooleanRepository(context);
    }

    @Test
    public void load() throws Exception {
        final File file = new File(context.getFilesDir(), BooleanRepository.FILE_NAME);
        try (final Writer fileWriter = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) {
            fileWriter.write(INPUT_STRING);
        }

        final boolean output = booleanRepository.load();
        assertThat(output).isEqualTo(INPUT_BOOL);
    }

    @Test
    public void save() throws Exception {
        booleanRepository.save(true);

        final File file = new File(context.getFilesDir(), BooleanRepository.FILE_NAME);
        try (final FileInputStream fileInputStream = new FileInputStream(file)) {
            final byte[] readBuffer = new byte[INPUT_STRING.length()];
            fileInputStream.read(readBuffer);
            assertThat(readBuffer).isEqualTo(INPUT_STRING);
        }
    }
}

Unten

Versuchte 1 Mock BufferedReader und PrintWriter

Warum verspotten Sie nicht zuerst den neuen "BufferedReader" und "PrintWriter" in der Methode mit "PowerMock"? Ich dachte. Ich wusste jedoch nicht, wie man "PowerMock" benutzt und gab auf, weil ich es nicht gut ersetzen konnte.

Versucht 2 Mock Context.openFileInput und Context.openFileOutput

Was wäre, wenn wir als nächstes "Context.openFileInput" und "Context.openFileOutput" verspotten könnten, um "ByteArrayInputStream" und "ByteArrayOutputStream" zurückzugeben? Ich dachte. Die Rückgabewerte von "Context.openFileInput" und "Context.openFileOutput" sind jedoch "FileInputStream" bzw. "FileOutputStream", sodass die Rückgabewerte nicht übereinstimmen und daher nicht möglich sind.

Versucht 3 Erstellen Sie eine Methode, die "InputStream", "OutputStream" zurückgibt, und verspotten Sie sie

Erstellen Sie eine Methode, die "InputStream" und "OutputStream" zurückgibt.

BooleanRepository.java


    InputStream getInputStream() throws FileNotFoundException {
        return context.openFileInput(FILE_NAME);
    }

    OutputStream getOutputStream() throws FileNotFoundException {
        return context.openFileOutput(FILE_NAME, Context.MODE_PRIVATE);
    }

Ändern Sie die zu testende Methode, um daraus zu lesen.

BooleanRepository.java


        try (final InputStream is = getInputStream();
        /* ... */
        try (final OutputStream os = getOutputStream();

Verspotten Sie diese Methode mit Mockito und geben Sie ByteArrayInputStream bzw. ByteArrayOutputStream zurück. Sie können das Byte-Array des Dateiinhalts an den Konstruktor für "ByteArrayInputStream" übergeben. Für ByteArrayOutputStream können Sie den Ausgabeinhalt mit byte [] lesen, indem Sie .toByteArray () ausführen.

BooleanRepositorySpec.java


public class MemoRepositorySpec {
    private static final boolean INPUT_BOOL = true;
    private static final byte[] INPUT_BYTES = String.valueOf(INPUT_BOOL).getBypes(StandardCharsets.UTF_8);

    @Spy
    private BooleanRepository booleanRepository;
    private Context context;

    @Before
    public void setUp() {
        context = mock(Context.class);
        booleanRepository = new BooleanRepository(context);
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void load() throws Exception {
        final ByteArrayInputStream is = new ByteArrayInputStream(INPUT_BYTES);
        doReturn(is).when(booleanRepository).getInputStream();

        final boolean output = booleanRepository.load();
        assertThat(output).isEqualTo(INPUT_BOOL);
    }

    @Test
    public void save() throws Exception {
        final ByteArrayOutputStream os = new ByteArrayOutputStream();
        doReturn(os).when(booleanRepository).getOutputStream();

        booleanRepository.save(true);
        assertThat(os.toByteArray()).containsExactly(INPUT_BYTES);
    }
}

Recommended Posts

Testen Sie eine Klasse, die einen Kontext empfängt und Dateien liest und schreibt
Erstellen Sie eine statische Datei, die Variablen mithilfe der ERB-Klasse erweitert
So testen Sie eine private Methode und verspotten sie teilweise in Java
Ich habe eine Klasse erstellt, die JUMAN und KNP aus Java verwenden kann
Warum nennt Java eine Datei eine Klasse?
Lesen einer Datei mit der Scannerklasse von Java
So testen Sie eine Klasse, die application.properties mit SpringBoot verarbeitet (Anfrage: darauf hingewiesen)