質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

ビルド

ソースコードを単体で実行可能なソフトウェアへ変換する過程をビルド(build)と呼びます

例外処理

例外処理(Exception handling)とは、プログラム実行中に異常が発生した場合、通常フローから外れ、例外として別の処理を行うようにデザインされたプログラミング言語構造です。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

解決済

1回答

1972閲覧

kotlinの単体テストコード作成で苦戦しています。

faaaypw

総合スコア1

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

ビルド

ソースコードを単体で実行可能なソフトウェアへ変換する過程をビルド(build)と呼びます

例外処理

例外処理(Exception handling)とは、プログラム実行中に異常が発生した場合、通常フローから外れ、例外として別の処理を行うようにデザインされたプログラミング言語構造です。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

0グッド

0クリップ

投稿2021/07/05 01:39

編集2021/07/08 06:17

前提・実現したいこと

kotlin独学2ヶ月目の初学者です。
ランダム関数を使って任意の天気情報を返すAPIを使った、簡単なお天気アプリを作成しています。
viewModelにてJSON文字列をStringに変換後APIに渡し、APIからはランダム関数を使ってJSON文字列で値がreturnされる、といったロジックのアプリです。APIはランダムに例外もスロ-してきます。

単体テスト作成で苦戦しているのでご助言いただきたいです。。

テスト観点としては以下を想定していますが、そもそもビルドエラ-してしまいます。
・APIから天気情報が正常に返却された場合に呼び出しもとの情報が正常に更新される確認

発生している問題・エラーメッセージ

kotlinx.serialization.json.internal.JsonDecodingException: Unexpected JSON token at offset 0: Expected '{, kind: CLASS' JSON input: at kotlinx.serialization.json.internal.JsonExceptionsKt.JsonDecodingException(JsonExceptions.kt:24) at kotlinx.serialization.json.internal.JsonExceptionsKt.JsonDecodingException(JsonExceptions.kt:32) at kotlinx.serialization.json.internal.JsonReader.fail(JsonReader.kt:333) at kotlinx.serialization.json.internal.StreamingJsonDecoder.beginStructure(StreamingJsonDecoder.kt:39) at jp.co.au.training.weather.GetAreaInfo$$serializer.deserialize(WeatherViewModel.kt:104) at jp.co.au.training.weather.GetAreaInfo$$serializer.deserialize(WeatherViewModel.kt:104) at kotlinx.serialization.json.internal.PolymorphicKt.decodeSerializableValuePolymorphic(Polymorphic.kt:63) at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:33) at kotlinx.serialization.json.Json.decodeFromString(Json.kt:85) at jp.co.au.training.weather.WeatherViewModel.getJsonWeatherInfo(WeatherViewModel.kt:116) at jp.co.au.training.weather.WeatherViewModelTest.getJsonWeatherInfo_apiReturnNormal_resultUpdateWeatherInfo(WeatherViewModelTest.kt:37) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:61) at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63) at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329) at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293) at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) at org.junit.runners.ParentRunner.run(ParentRunner.java:413) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)

該当のソースコード

kotlin

1class WeatherViewModelTest { 2 3 @get:Rule 4 val instantTaskExecutorRule = InstantTaskExecutorRule() 5 6 @Test 7 fun getJsonWeatherInfo_apiReturnNormal_resultUpdateWeatherInfo() { 8 9 // mockインスタンスを生成 10 val mockWeatherApi = mockk<WeatherApi>(relaxed = true) 11 12 // テスト対象のクラスのインスタンスを生成 13 val testTargetWeatherViewModel = WeatherViewModel(mockWeatherApi, SavedStateHandle()) 14 val result = testTargetWeatherViewModel.resultJsonWeather 15 16 // mockインスタンスに任意のパターンを設定 17 every { mockWeatherApi.fetchJsonWeather("tokyo") } returns "weather=rainy" 18 19 // テスト対象のメソッドを呼び出す 20 testTargetWeatherViewModel.getJsonWeatherInfo() 21 22 assertEquals(result, "weather=rainy" ) 23 24 } 25} 26

kotlin

1@HiltViewModel 2class WeatherViewModel @Inject constructor( 3 private var weatherApi: WeatherApi, 4 private val savedStateHandle: SavedStateHandle, 5) : ViewModel() { 6 7****中略***** 8 9 fun getJsonWeatherInfo() { 10 initializeData() 11 val jsonAreaInfo = AreaInfo("tokyo", "2021-06-22") 12 val stringAreaInfo = Json.encodeToString(jsonAreaInfo) 13 try { 14 resultJsonWeather = weatherApi.fetchJsonWeather(stringAreaInfo) 15 } catch (e: UnknownException) { 16 isGetWeather = true 17 } 18 19 val resultStringWeather = resultJsonWeather?.let { Json.decodeFromString<GetAreaInfo>(it) } 20 currentWeather = resultStringWeather?.weather 21 currentMinTemp = resultStringWeather?.minTemp 22 currentMaxTemp = resultStringWeather?.maxTemp 23 24 val weatherString = currentWeather ?: return 25 try { 26 currentWeatherImage = selectWeatherImage(weatherString) 27 } catch (e: SelectImageException) { 28 isSetImage = false 29 } 30 } 31

kotlin

1@Serializable 2data class AreaInfo( 3 val area: String, 4 val date: String 5) 6 7@Serializable 8data class GetAreaInfo( 9 val weather: String, 10 val maxTemp: Int, 11 val minTemp: Int, 12 val date: String 13) 14 15

試したこと

JSONのデコードに関するエラーが出ているようなので、
viewMolde内のgetJsonWeatherInfo()で「// 取得したJSON文字列からデータクラスを生成」以降をコメントアウトするとビルドが通りました。
テスト対象の関数の、ある部分のみをテストしたい場合のコーティング方法はあるのでしょうか
また、上記でテスト実行されたものの、Expected :nullとなりテストに失敗してしまいます。
実機で動作確認する分には正常に動作しているように見えるので、テストコードに不備があるのではと思っています。

補足情報(FW/ツールのバージョンなど)

・AndroidStudio4.2.1
・kotlin plugin version 202-1.5.10

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2021/07/06 01:13

WeatherApi の定義がないのでよく分かりませんが、returns "weather=rainy" の部分が JSON 文字列になってないのが気になります…。
faaaypw

2021/07/06 01:44

ご指摘ありがとうございます。APIに関するソースコードを追記しました。
faaaypw

2021/07/08 06:11 編集

// mockインスタンスにパターンを設定 every { mockWeatherApi.fetchJsonWeather("{\"area\":\"tokyo\",\"date\":\"2021-06-22\"}") } returns "{\"weather\":\"sunny\",\"maxTemp\":16,\"minTemp\":-8,\"date\":\"2021-06-22\"}" // テスト対象のメソッドを呼び出す testTargetWeatherViewModel.getJsonWeatherInfo() val result = testTargetWeatherViewModel.resultJsonWeather assertEquals( result,"{\"weather\":\"sunny\",\"maxTemp\":16,\"minTemp\":-8,\"date\":\"2021-06-22\"}" ) ↑ ご指摘いただいたことをヒントに、returnsとAPIに渡す引数をJSON文字列に修正し、さらにresultの宣言を関数呼び出しの後に記述したところ、テスト成功しました。本当にありがとうございました!!
guest

回答1

0

自己解決

// mockインスタンスにパターンを設定
every {
mockWeatherApi.fetchJsonWeather("{"area":"tokyo","date":"2021-06-22"}")
} returns "{"weather":"sunny","maxTemp":16,"minTemp":-8,"date":"2021-06-22"}"

// テスト対象のメソッドを呼び出す
testTargetWeatherViewModel.getJsonWeatherInfo()
val result = testTargetWeatherViewModel.resultJsonWeather
assertEquals( result,"{"weather":"sunny","maxTemp":16,"minTemp":-8,"date":"2021-06-22"}" )

returnsとAPIに渡す引数をJSON文字列に修正し、さらにresultの宣言を関数呼び出しの後に記述したところ、テスト成功しました。

投稿2021/07/08 06:12

faaaypw

総合スコア1

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問