何时在单元测试中使用模拟对象 [英] When to use mock objects in unit tests

查看:65
本文介绍了何时在单元测试中使用模拟对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道关于模拟和测试有很多问题,但是我发现没有什么问题可以完美地帮助我,所以我仍然在理解以下方面有困难:

I'm aware that there are many questions about mocking and testing, but I didn't find any that helped me perfectly, so I still have problems understanding the follwing:

如果我弄错了,请纠正我,但是据我所知,单元测试用于隔离地测试一个特定类的业务逻辑,并且如果有外部需要的任何对象,它们将被模拟.因此,例如,如果我有一个简单城市居民的管理系统,该系统将居民添加到列表中并按姓名返回居民(假设:居民仅包含一些基本个人信息),如下所示:

Please correct me if I got this wrong, but as far as I see, unit tests are used to test the business logic of one particular class in isolation and if there are any objects needed from the outside they will be mocked. So for example if I have a management system for citizens of a simple city that adds citizens to a list and returns the citizen by their names (Assumtion: citizens consist of only a few basic personal information), like this:

public class ProcessClass {

    ArrayList<Citizen> citizenList = new ArrayList<Citizen>();

    public void addCitizen(Citizen citizen) {
        citizenList.add(citizen);
    }

    public Citizen getByName(String name) {
        for (Citizen c : citizenList) {
            if (c.getName().equals(name)) {
                return c;
            }
        }
        return null;
    }

}

如果现在我要对我的 ProcessClass 进行单元测试,我是否将 Citizen 视为必须被模拟的外部功能,还是只创建一个市民用于测试?如果它们是模拟的,由于模拟对象不包含参数,我将如何测试该方法以按其名称获取对象?

If now I want to unit test my ProcessClass do I consider Citizen as an external feature that has to be mocked, or do I simply just create a Citizen for test purposes? If they are mocked, how would I test the method to get the object by its name, since the mock object is not containing the parameters?

推荐答案

如果它们是模拟的,由于模拟对象不包含参数,我将如何测试通过名称获取该对象的方法?

If they are mocked, how would I test the method to get the object by its name, since the mock object is not containing the parameters?

例如,您可以使用嘲笑来模拟对 getName 的调用:

You can mock the call to getName, using mockito for example:

Citizen citizen = mock(Citizen.class);
when(citizen.getName()).thenReturn("Bob");

以下是您的方法测试的示例

ProcessClass processClass = new ProcessClass();

Citizen citizen1 = mock(Citizen.class);
Citizen citizen2 = mock(Citizen.class);
Citizen citizen3 = mock(Citizen.class);

@Test
public void getByName_shouldReturnCorrectCitizen_whenPresentInList() {
    when(citizen1.getName()).thenReturn("Bob");
    when(citizen2.getName()).thenReturn("Alice");
    when(citizen3.getName()).thenReturn("John");

    processClass.addCitizen(citizen1);
    processClass.addCitizen(citizen2);
    processClass.addCitizen(citizen3);

    Assert.assertEquals(citizen2, processClass.getByName("Alice"));
}

@Test
public void getByName_shouldReturnNull_whenNotPresentInList() {
    when(citizen1.getName()).thenReturn("Bob");

    processClass.addCitizen(citizen1);

    Assert.assertNull(processClass.getByName("Ben"));
}

注意:

我建议嘲笑.假设您编写了100个测试,并以这种方式实例化 Citizen

I would recommend mocking. Let's say you write 100 tests where you instantiate a Citizen class this way

Citizen c = new Citizen();

几个月后,您的构造函数更改为采用一个参数,该参数本身是一个对象,例如 City 类.现在,您必须返回并更改所有这些测试并编写:

and a few months later, your constructor changes to take an argument, which is an object itself, class City for example. Now you have to go back and change all these tests and write:

City city = new City("Paris");
Citizen c = new Citizen(city);

如果您以嘲笑 Citizen 开始,则不需要.

If you mocked Citizen to start with, you wouldn't need to.

现在,因为它是POJO,并且其getName方法的构造函数可能不会更改,所以不应该进行模拟.

Now, as it is POJO and its constructor of the getName method might not change, not mocking should still be ok.

这篇关于何时在单元测试中使用模拟对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆