首页 \ 问答 \ 封装和嘲弄(Encapsulating and mocking)

封装和嘲弄(Encapsulating and mocking)

假设我有一个简单依赖的类:

public interface Dependency {
    int doSomething(int value);
    void doMore(int value);
    int doALotMore(int value);
}

public final class A implements SomeInterface {
    private final Dependency dep;

    public A (Dependency dep) {
        this.dep = dep;
    }

    @Override
    public int add(final int x) {
        dep.doMore(x);
        return x + dep.doSomething(x) + dep.doALotMore(x);
    }
}

我正在使用模拟编写测试:

public class TestA {
    private Dependency mockDep;
    private SomeInterface a;

    @Before
    public void setUp() {
        mockDep = Mockito.mock(Dependency.class);
        a = new A(mockDep);
    }

    @Test
    public void shouldAdd() {
        final int x = 5;
        when(mockDep.doSomething(x)).thenReturn(6);
        when(mockDep.doALotMore(x)).thenReturn(7);

        int actual = a.add(x);

        assertThat(actual, is(18));

        verify(mockDep, times(1)).doSomething();
        verify(mockDep, times(1)).doALotMore();
        verify(mockDep, times(1)).doMore();

        verifyNoMoreInteractions(mockDep);
    }
}

到现在为止还挺好。

所以问题是:我们是否通过验证依赖关系的使用方式来违反AA封装? 是否真的需要测试依赖性是否以这种方式使用? 我们不应该像一个黑盒子一样测试A (从测试用例中删除verify调用并只留下assertThat )? 在这种情况下如何处理依赖?

我问的原因是我发现自己编写了大量的验证依赖代码,似乎我们开始测试关于类的实际内部实现细节。 我对此感到不舒服,因为当我尝试以另一种方式重写此实现细节时,我需要重写测试用例,尽管例如add的结果将是相同的。 如果我将我的类测试为黑盒子,我可以改变实现细节,并且仍然确保给定输入将提供相同的输出。

或者有必要实际测试实现细节,这是单元测试本身的重点? 这对我来说似乎有些不对劲。

请考虑这个测试:

 public class TestA {
    private Dependency mockDep;
    private SomeInterface a;
    private final int x = 5;

    @Before
    public void setUp() {
        mockDep = Mockito.mock(Dependency.class);
        a = new A(mockDep);

        when(mockDep.doSomething(x)).thenReturn(6);
        when(mockDep.doALotMore(x)).thenReturn(7);
    }

    @Test
    public void shouldAdd() {
        int actual = a.add(x);

        assertThat(actual, is(18));
    }
}

Suppose I have class with simple dependency:

public interface Dependency {
    int doSomething(int value);
    void doMore(int value);
    int doALotMore(int value);
}

public final class A implements SomeInterface {
    private final Dependency dep;

    public A (Dependency dep) {
        this.dep = dep;
    }

    @Override
    public int add(final int x) {
        dep.doMore(x);
        return x + dep.doSomething(x) + dep.doALotMore(x);
    }
}

And I'm writing test using mocks:

public class TestA {
    private Dependency mockDep;
    private SomeInterface a;

    @Before
    public void setUp() {
        mockDep = Mockito.mock(Dependency.class);
        a = new A(mockDep);
    }

    @Test
    public void shouldAdd() {
        final int x = 5;
        when(mockDep.doSomething(x)).thenReturn(6);
        when(mockDep.doALotMore(x)).thenReturn(7);

        int actual = a.add(x);

        assertThat(actual, is(18));

        verify(mockDep, times(1)).doSomething();
        verify(mockDep, times(1)).doALotMore();
        verify(mockDep, times(1)).doMore();

        verifyNoMoreInteractions(mockDep);
    }
}

So far so good.

So the question is: do we violate encapsulation of class A by verifying how exactly the dependency was used? Does it really needed to test that dependency was used in exactly that way? Shouldn't we test A like a black-box (delete verify invocations from test case and leave just assertThat)? And how to deal with dependencies in such case?

The reason I'm asking is that I caught myself writing good amount of verification dependency code and it seems that we start to test actual internal realization details about class. And I feel uncomfortable about that because when I will try to rewrite this realization details in another way I need to rewrite test cases although the result of add for example will be the same. If I would test my class as a black-box I can change realization details and still be sure that given input will give same output.

Or it is necessary to actually test exactly the realization details and that is the point of unit-test itself? It seems somewhat wrong for me.

Consider this test instead:

 public class TestA {
    private Dependency mockDep;
    private SomeInterface a;
    private final int x = 5;

    @Before
    public void setUp() {
        mockDep = Mockito.mock(Dependency.class);
        a = new A(mockDep);

        when(mockDep.doSomething(x)).thenReturn(6);
        when(mockDep.doALotMore(x)).thenReturn(7);
    }

    @Test
    public void shouldAdd() {
        int actual = a.add(x);

        assertThat(actual, is(18));
    }
}

原文:https://stackoverflow.com/questions/46080150
更新时间:2023-03-11 21:03

最满意答案

首先要做的事情是:IntentService仅用于执行主线程之外的任务队列。 因此,每次要检查更新时都必须创建一个新的:为此,请参阅Alarm Manager

但这不一定是最好的方法。 您可以尝试推送通知方法,而不是轮询服务器以进行更改。


First things first: IntentService is designed only to execute a queue of tasks off the main thread. So you must create a new one every time you want to check for updates: for that see Alarm Manager

But this is not necessarily the best way to do it. Instead of you polling the server for changes, try the push notifications approach.

相关问答

更多
  • 当您将bounce()附加到click事件时,您可以在该函数中使用this ,但除此之外,您需要定义“this”。 您可以使用bind,或将其更改为您的元素。 试试这个: var bounce = function() { var element = $('someID'); // cache it here or outside the function element.set('tween', {duration: 1500, transition: 'bounce:out'}); ...
  • 你的意思是你需要在当天的特定时间在WCF服务中调用操作? 您可以在.exe应用程序中简单地创建服务的客户端,并添加调用该客户端的计划任务。 Do you mean you need to call an operation in a WCF service at a certain time in the day? You can simply create a client for the service in an .exe application and add a scheduled task wh ...
  • 使用Sticky标志启动服务是正常的方法。 Starting a service on boot with a Sticky flag is the normal way of doing this.
  • 有两种方法可以满足您的要求。 的TimerTask 报警管理器类 TimerTask有一种方法可以在给定的特定时间间隔内重复活动。 请看下面的示例示例。 Timer timer; MyTimerTask timerTask; timer = new Timer(); timerTask = new MyTimerTask(); timer.schedule ( timerTask, startingInterval, repeatingInterval ); private class MyTim ...
  • 这可能是我对服务主机的实现还是与本地网络有关? 如果您看到发送FIN意味着实体(客户端和服务器)故意关闭连接。 因此在应用程序的实现而不是与网络。 过渡到关闭等待意味着接收并确认了FIN,接收FIN的一方需要close 。 The above problem is solved. It appears that the relay service communicates with Azure using TCP port 5671. Our network firewall did not open up ...
  • 您没有正确地调用定期功能,请参阅MooTools文档 。 在你的例子中,你运行一次函数并尝试使用它的返回值的周期函数(因此你的第一条消息是直接记录的,而不是在1000ms延迟之后): var Main = new Class({ Implements: [Options], options: { releaseDate: '1 January, 2010' }, initialize: function(options){ this.setOptions(options) ...
  • 首先要做的事情是:IntentService仅用于执行主线程之外的任务队列。 因此,每次要检查更新时都必须创建一个新的:为此,请参阅Alarm Manager 但这不一定是最好的方法。 您可以尝试推送通知方法,而不是轮询服务器以进行更改。 First things first: IntentService is designed only to execute a queue of tasks off the main thread. So you must create a new one every t ...
  • 最后,我找到了解决该问题的简单方法。 一切都很简单: 转到Autoscaling组(您可以在EC2仪表板上找到 - > Autoscaling部分); 创建计划的操作(在这种情况下,可以为容器实例指定必要的频率); 保存配置。 实例将在指定时间内添加。 在我的情况下,我还需要在1小时内缩小此实例。 Finally I found out an easy solution for that problem. Everything was quite simple: Go to Autoscaling grou ...

相关文章

更多

最新问答

更多
  • 获取MVC 4使用的DisplayMode后缀(Get the DisplayMode Suffix being used by MVC 4)
  • 如何通过引用返回对象?(How is returning an object by reference possible?)
  • 矩阵如何存储在内存中?(How are matrices stored in memory?)
  • 每个请求的Java新会话?(Java New Session For Each Request?)
  • css:浮动div中重叠的标题h1(css: overlapping headlines h1 in floated divs)
  • 无论图像如何,Caffe预测同一类(Caffe predicts same class regardless of image)
  • xcode语法颜色编码解释?(xcode syntax color coding explained?)
  • 在Access 2010 Runtime中使用Office 2000校对工具(Use Office 2000 proofing tools in Access 2010 Runtime)
  • 从单独的Web主机将图像传输到服务器上(Getting images onto server from separate web host)
  • 从旧版本复制文件并保留它们(旧/新版本)(Copy a file from old revision and keep both of them (old / new revision))
  • 西安哪有PLC可控制编程的培训
  • 在Entity Framework中选择基类(Select base class in Entity Framework)
  • 在Android中出现错误“数据集和渲染器应该不为null,并且应该具有相同数量的系列”(Error “Dataset and renderer should be not null and should have the same number of series” in Android)
  • 电脑二级VF有什么用
  • Datamapper Ruby如何添加Hook方法(Datamapper Ruby How to add Hook Method)
  • 金华英语角.
  • 手机软件如何制作
  • 用于Android webview中图像保存的上下文菜单(Context Menu for Image Saving in an Android webview)
  • 注意:未定义的偏移量:PHP(Notice: Undefined offset: PHP)
  • 如何读R中的大数据集[复制](How to read large dataset in R [duplicate])
  • Unity 5 Heighmap与地形宽度/地形长度的分辨率关系?(Unity 5 Heighmap Resolution relationship to terrain width / terrain length?)
  • 如何通知PipedOutputStream线程写入最后一个字节的PipedInputStream线程?(How to notify PipedInputStream thread that PipedOutputStream thread has written last byte?)
  • python的访问器方法有哪些
  • DeviceNetworkInformation:哪个是哪个?(DeviceNetworkInformation: Which is which?)
  • 在Ruby中对组合进行排序(Sorting a combination in Ruby)
  • 网站开发的流程?
  • 使用Zend Framework 2中的JOIN sql检索数据(Retrieve data using JOIN sql in Zend Framework 2)
  • 条带格式类型格式模式编号无法正常工作(Stripes format type format pattern number not working properly)
  • 透明度错误IE11(Transparency bug IE11)
  • linux的基本操作命令。。。