I'm addicted to how to write test code for a class that receives Context
in the constructor and uses Context.openFileInput
and Context.openFileOutput
, so I'll write it down.
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);
}
}
}
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);
}
}
}
BufferedReader
and PrintWriter
Why not mock the new BufferedReader
and PrintWriter
in the method with PowerMock
first? I thought.
However, I didn't know how to use PowerMock
and gave up because I couldn't replace it well.
Context.openFileInput
and Context.openFileOutput
Next, what if we could mock Context.openFileInput
and Context.openFileOutput
to return ByteArrayInputStream
and ByteArrayOutputStream
? I thought.
However, the return values of Context.openFileInput
and Context.openFileOutput
are FileInputStream
and FileOutputStream
, respectively, so the return values do not match, so it is impossible.
, ʻOutputStream
and mock itCreate a method that returns ʻ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);
}
Change the method under test to read from it.
BooleanRepository.java
try (final InputStream is = getInputStream();
/* ... */
try (final OutputStream os = getOutputStream();
Mock that method with Mockito
and return ByteArrayInputStream
and ByteArrayOutputStream
respectively.
You can pass the byte array of the file contents to the constructor for ByteArrayInputStream
.
For ByteArrayOutputStream
, you can read the output contents in byte [] by doing.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