【问题标题】:Android Unit Testing: How to make a class more testable?Android单元测试:如何让一个类更易测试?
【发布时间】:2016-01-26 10:26:38
【问题描述】:

我一直在开发 Android 应用程序,但没有编写任何单元测试。最近我开始学习它并尝试使用 JUnit 来测试我的 android 应用程序。

我发现大多数时候我都会在 API 调用中遇到错误,但我仍然无法理解如何为它们编写单元测试(以及如何使原始代码可测试)。

让我解释一下下面的函数:

我正在运行一个函数调用 setOffenceList()。函数内部发生了多个动作。

i) 加载 RestClient 并传递 URL。

ii) RestClient 与 JSON api 对话并获得响应

ii) 我在 onSuccess(String response) 函数中获取响应

iii) 解析 JSON 数据并存储在数组中

iv) 如果成功,我将在列表视图中显示数据(否则显示错误消息)

这是代码:

public class OffenceFrag extends Fragment {


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.frag_offence, container, false);
        //run API call
        setOffenceList();
        return view;
    }

    private void setOffenceList() {
        String url = Paths.SITE_URL ;
        RestClient.get(url, null, new AsyncHttpResponseHandler() {

            @Override
            public void onStart() {
                Toast.makeText(getActivity(), "Loading offences...", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onSuccess(String response) {

                //Parse JSON
                JSONArray jsonArray;
                try {

                    JSONObject jsonObj = new JSONObject(response);
                    if(jsonObj.getString("status").equalsIgnoreCase("Success")){

                        jsonArray = new JSONArray(jsonObj.getString("data"));
                        if(jsonArray.length() > 0){
                            for (int i = 0; i < jsonArray.length(); i++) {

                                JSONObject row = jsonArray.getJSONObject(i);
                                OffenceORM off = new OffenceORM();
                                off.setOffenceId(row.getString("offence_id"));
                                off.setPhoto(row.getString("photo"));
                                off.setSubmittedBy(row.getString("submitted_by"));
                                offenceList.add(off);
                            }
                        }   

                        //Success: Show the list view
                        setOffenceAdapter();
                        Toast.makeText(getActivity(), "Successfully Loaded", Toast.LENGTH_LONG).show();

                    } else {
                        //Failed: show error message
                        Toast.makeText(getActivity(), "There are no offences submitted under project", Toast.LENGTH_LONG).show();
                    }

                } catch (Exception e) {
                    Log.e("exception", e.getMessage());
                }
            }

            @Override
            public void onFailure(Throwable error, String content) {
                Log.e("failed", error.getMessage());
            }

            @Override
            public void onFinish() {

            }
        });
    }


}//end

我真的不明白如何为上述代码编写测试函数。

您能告诉我如何将这段代码分解为可测试的部分并为它们编写单元测试函数吗?

非常感谢!

【问题讨论】:

  • 一种方法是编写一个集成测试来练习 REST API。见stackoverflow.com/questions/10752/…。在单元测试方法中,您通常会模拟 LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState,将它们传递给 OffenceFrag. onCreateView() 并断言 OffenceFrag 符合您的预期

标签: java android api unit-testing junit


【解决方案1】:

只有并且只有好的设计才能帮助您更轻松地进行单元测试。这就是存在测试驱动开发的原因。这样你就不会选择错误的设计。

当您进行单元测试时,您只需测试您编写的代码并使用 Android 提供的模拟对象来测试 android Api 调用。

就其他 Api 的问题而言,不是您的 Api 开发人员的问题。您可以使用 Mockito 之类的模拟框架在调用其他 API 代码时测试代码的功能。如果您正在开发自己的 API,请单独测试 API 代码。

良好的设计必须遵循设计原则,例如

  • S – 单一职责原则
  • O——开闭原则
  • L – Liskov 替换原则
  • I – 接口隔离原则
  • D – 依赖倒置原则

要点:

  • 每个单元测试用例调用一个断言方法
  • 不要仅仅为了测试而修改类。
  • 接口的使用
  • 不要在一种方法中放置过多的语句或功能。
  • 不要开设太大的课程。
  • 使用 TDD.......更多

对糟糕的设计代码进行单元测试完全是浪费。因为每次您对课程进行一些更改时,测试都会中断。在 Android 中,这种情况会发生得更多。因为您被 Android 生命周期方法所困。

仔细抽象出你想在他们自己的类中测试的功能。

这将使您的应用程序代码更加健壮、简单和清晰。

【讨论】:

  • one assert method call per unit test case - 这并不总是可能的。例如:nobody 在一个测试中检查 null,在另一个测试中检查结果的值。
【解决方案2】:

你在 Fragment 中做的东西太多,很难测试和维护。

我在我的项目中使用 MVP 模式,它允许将表示层与逻辑分开,避免将所有代码放在片段/活动中。

查看这篇文章:http://antonioleiva.com/mvp-android/

以及 GitHub 中的相应代码示例:https://github.com/antoniolg/androidmvp

【讨论】:

    【解决方案3】:

    Rohit Khatkar 关于使用 TDD 的建议对于您开发的下一个代码当然值得考虑。但是,既然这段代码存在并且您在问“如何将这段代码分解为可测试的部分”:您首先可以忽略可测试性,而只是尝试将这段代码分解为更小的部分:Exline 类定义和拆分方法,就像一般优化可读性一样。您会发现一些冗余(for 循环周围的 if)。

    因此,每个生成的方法对其他类的依赖可能会更少。然后,您可以专注于减少这些依赖关系。查看 Michael Feather 关于处理遗留代码的书,了解一系列打破依赖关系的方法。编辑:有人提取了一个依赖破坏技术列表(不过只有高级描述):http://rubyexperiences.blogspot.de/2005/12/dependency-breaking-techniques-from.html

    【讨论】:

      猜你喜欢
      • 2013-04-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-16
      • 2017-09-11
      • 2021-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多