封装和嘲弄(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); } }
到现在为止还挺好。
所以问题是:我们是否通过验证依赖关系的使用方式来违反
A
类A
封装? 是否真的需要测试依赖性是否以这种方式使用? 我们不应该像一个黑盒子一样测试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 testA
like a black-box (deleteverify
invocations from test case and leave justassertThat
)? 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
最满意答案
首先要做的事情是: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.
相关问答
更多-
TCP/IP模型是一个________。[2023-05-19]
a -
当您将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'}); ...
-
下列中不属于面向对象的编程语言的是?[2022-05-30]
a -
WCF周期性函数(WCF Periodical Function)[2023-07-23]
你的意思是你需要在当天的特定时间在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期刊问题(Mootools Periodical Problems)[2023-01-20]
您没有正确地调用定期功能,请参阅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 ...