[JAVA] Tester une classe qui reçoit un contexte et lit et écrit des fichiers

Je suis accro à la façon d'écrire du code de test pour les classes qui reçoivent Context dans le constructeur et utilisent Context.openFileInput et Context.openFileOutput, donc je l'écrirai.

Classe à tester

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);
        }
    }
}

Conclusion Utilisation * Robolectric *

Avec * Robolectric *, les tests dépendants d'Android peuvent également être exécutés sur la JVM.

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);
        }
    }
}

Au dessous de

J'ai essayé 1 Mock BufferedReader et PrintWriter

Pourquoi ne pas se moquer des nouveaux BufferedReader et PrintWriter dans la méthode avec PowerMock en premier? J'ai pensé. Cependant, je ne savais pas comment utiliser PowerMock et j'ai abandonné car je ne pouvais pas bien le remplacer.

J'ai essayé 2 Mock Context.openFileInput et Context.openFileOutput

Ensuite, que se passerait-il si nous pouvions nous moquer de Context.openFileInput et Context.openFileOutput pour renvoyer ByteArrayInputStream et ByteArrayOutputStream? J'ai pensé. Cependant, les valeurs de retour de Context.openFileInput et Context.openFileOutput sont respectivement FileInputStream et FileOutputStream, donc les valeurs de retour ne correspondent pas, donc c'est impossible.

Essayé 3 Créez une méthode qui renvoie ʻInputStream, ʻOutputStream et moquez-la

Créez une méthode qui renvoie ʻInputStream, ʻOutputStream,

BooleanRepository.java


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

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

Modifiez la méthode testée pour en lire.

BooleanRepository.java


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

Simulez la méthode avec «Mockito» et renvoyez respectivement «ByteArrayInputStream» et «ByteArrayOutputStream». Vous pouvez passer le tableau d'octets du contenu du fichier au constructeur pour ByteArrayInputStream. Pour ByteArrayOutputStream, vous pouvez lire le contenu de sortie avec byte [] en faisant .toByteArray ().

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

Tester une classe qui reçoit un contexte et lit et écrit des fichiers
Créez un fichier statique qui développe les variables à l'aide de la classe ERB
Comment tester une méthode privée et la simuler partiellement en Java
J'ai créé une classe qui peut utiliser JUMAN et KNP de Java
Pourquoi Java appelle-t-il un fichier une classe?
Lire un fichier à l'aide de la classe Scanner de Java
Comment tester une classe qui gère application.properties avec SpringBoot (requête: signalée)