Android单元测试:如何让课程更具可测性?

时间:2016-01-26 10:26:39

标签: java android api unit-testing junit

我一直在开发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

我无法理解如何将测试功能编写为类似上述代码的内容。

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

非常感谢!

3 个答案:

答案 0 :(得分:5)

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

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

至于其他Api有问题,而不是Api开发者的问题不是你的问题。您可以使用Mockito等模拟框架在调用其他API代码时测试代码的功能。如果您正在开发自己的API,请单独测试API代码。

必须遵循设计原则才能获得良好的设计,例如

  • S - 单一责任原则
  • O - 开放式原则
  • L - Liskov替代原则
  • I - 界面隔离原则
  • D - 依赖性倒置原则

重点:

  • 每个单元测试用例一个断言方法调用
  • 不要仅仅为了测试而修改类。
  • 使用接口
  • 不要在一种方法中加入太多的陈述或功能。
  • 不要做太大的课程。
  • 使用TDD .......更多

单元测试严重的设计代码是完全浪费。每次对类进行一些更改时,测试都会中断。在Android中,这将发生更多。因为你坚持使用Android生命周期方法。

小心抽象出你想要在自己的类中测试的功能。

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

答案 1 :(得分:1)

你在Fragment中做了太多的事情,很难测试和维护。

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

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

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

答案 2 :(得分:1)

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

作为一种效果,每个结果方法可能对其他类的依赖性较小。然后,您可以专注于减少这些依赖项。查看Michael Feather关于处理遗留代码的书籍,其中介绍了一系列破坏依赖关系的方法。编辑:有人提取了依赖性破坏技术列表(但只有高级描述):http://rubyexperiences.blogspot.de/2005/12/dependency-breaking-techniques-from.html