English 中文(简体)
单一州和单位测试
原标题:Singleton and unit testing

有效 Java有以下关于单州单位检测的声明:

把一个班子变成一个单一州会使其难以测试客户,因为除非它实施一个称为其类别的接口,否则不可能将一个小区改为一个小区。

谁能解释为什么如此?

问题回答

你可以进行思考,重新确定你的单一吨物体,以防止试验相互影响。

@Before
public void resetSingleton() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
   Field instance = MySingleton.class.getDeclaredField("instance");
   instance.setAccessible(true);
   instance.set(null, null);
}

Ref: unit-testing-singletons

问题在于单州本身;这本书指出,如果某类国家试图测试,则取决于。 a 单一州,你可能会有问题。

否则,即(1)使单一州采用接口,(2)利用这一接口向贵阶层注入单一吨。

例如,单一州通常直线出现:

public class MyClass
{
    private MySingleton __s = MySingleton.getInstance() ;

    ...
}

<代码>MyClass 现在可能很难自动测试。 例如,正如“Boris Pavlović”在其答复中指出的那样,如果单一州的行为是以系统时间为依据的,那么你的测试现在也取决于系统的时间,而且你可能无法测试那些情况,即取决于该周的一天。

然而,如果贵国的单一国家“实施其类型”的接口,那么只要你通过该接口,你仍可以使用该接口的单一吨,<>>>。

public class SomeSingleton
    implements SomeInterface
{
    ...
}

public class MyClass
{
    private SomeInterface __s ;

    public MyClass( SomeInterface s )
    {
        __s = s ;
    }

    ...
}

...

MyClass m = new MyClass( SomeSingleton.getInstance() ) ;

从测试的角度来看, 现在,如果,你不予以照料。 一些单一州()不是单一州:你也可以通过你想要的任何其他执行,包括单一州的执行,但你很可能使用某种模型,由你进行检测。

BTW,这就是:

public class MyClass
{
    private SomeInterface __s = SomeSingleton.getInstance() ;

    public MyClass()
    {
    }

    ...
}

这在运行时间仍然如此,但为了测试,现在又依赖于<代码>。 SomeSingleton .

检查需要接口,因为你重新做的是把真正的基本行为替换为一种使你需要测试的主人。 由于客户只处理一个接口参考类型,因此没有必要知道执行是什么。

你可以在没有接口的情况下 t一个具体类别,因为你可以在没有测试客户知道的情况下取代行为。 在该案中,它是一个完全新的类别。

所有班级,无论是单一州还是非单一州,都是如此。

我认为,这实际上取决于《singleton Access patterns的实施。

例如

MySingleton.getInstance()

测验精度极低

MySingletonFactory mySingletonFactory = ...
mySingletonFactory.getInstance() //this returns a MySingleton instance or even a subclass

没有提供关于使用单一州的事实的任何信息。 因此,你可以自由更换工厂。

<>strong>NOTE:单一州的定义是,只有一例提出申请,但其获得或储存的方式不一定是固定手段。

It s oh so simple.

In unit-testing, you want to isolate your SUT (the class you re testing). You don t want to test a bunch of classes, because that would defeat the purpose of unit-testing.

But not all classes do everything on their own, right? Most classes use other classes to do their work, and they kind of mediate between other classes, and add a bit of their own, to get the final result.

问题在于——你不关心贵专业大学的班级如何取决于工作。 请你注意您的SUT与这些类别的工作。 这就是你为什么要<>stub或 mock。 表2. 按部门分列的所需特别服务 你们也可以使用这些cks子,因为你可以把.子作为你的SUT的建筑参数。

采用单一吨法,坏之处在于:getInstance()方法在全球范围内可使用。 这意味着,你通常从一个类别,而不是depending <>em>,在你后来的界面上打上。 因此,在你想要测试你的SUT时,它不可能做到replace>。

解决办法不是使用Sneaky 公开静态MySingleton AccessInstance(),而是在interface上使用<><<><><<<>><<>>>><<>>>><>>><<>>>>><>>><>><>>>><>>><>><>>>><>>>><>>>>>><>>>><>>>><>>>>><>>>>><>>>>>><>>>>>>>><>>>>>>><>>>>>>><>>>>>>>>>>><>>>>>>><>>>>>>>>>><>>>>>>><>>>>>>>>><>>>>>>><>>>>>>>><>>>>><>>>>>>>> 如果需要的话,你可在上通过:

单一吨物体是在不受外部控制的情况下制造的。 在同一本书的其他章节中,Bloch建议使用enum作为违约单一州执行。 举一个例子。

public enum Day {
  MON(2), TUE(3), WED(4), THU(5), FRI(6), SAT(7), SUN(1);

  private final int index;

  private Day(int index) {

    this.index = index;
  }

  public boolean isToday() {

    return index == new GregorianCalendar().get(Calendar.DAY_OF_WEEK);
  }
}

让我们说,我们有一部法律,只能在周末执行:

public void leisure() {

  if (Day.SAT.isToday() || Day.SUN.isToday()) {

    haveSomeFun();
    return;
  }

  doSomeWork();
}

测试休闲方法将十分困难。 其执行将取决于何时执行。 如果在一周内执行<代码>doSomeWork(>,则在周末使用 haveSomeFun(

在此情况下,我们需要使用一些重型工具,如PowerMock,拦截GregorianCalendar的构造者,返回一个模拟仪,在两个试验案例中,将相当于一个星期天或周末的索引,测试leisure两种执行途径。

it’s impossible to substitute a mock implementation for a singleton

情况并非如此。 你可以把你的单一吨位 sub为后盾,并注入一ck。 或者,您可使用PowerMock至模拟静态方法。 然而,对单一州进行模拟的必要性可能说明设计不好。

The real problem is Singletons when abused turn into dependency magnets. Since they are accessible everywhere, it can appear more convenient to put the functions you need in them rather than delegating to an appropriate class, especially for programmers new to OOP.

testability problem is now You with a bunch ofunitons that are available by their Object under test. 尽管该物体可能只在单一州使用一小部分方法,但你仍然需要对每个单一州进行模拟,并标明哪些方法依赖。 静态状态(摩纳哥模式)的单一州甚至更糟,因为你可以估计,各物体之间的互动受到单一州的影响。

谨慎使用、单一州和可检测性可以一起使用。 例如,在没有DI框架的情况下,你可以使用单一州作为你的工厂和服务单位,而你可以设置这种设施,为您的终端至终端测试建立一个假的服务层。

可查阅

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.lang.reflect.Field;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class DriverSnapshotHandlerTest {

private static final String MOCKED_URL = "MockedURL";
private FormatterService formatter;

@SuppressWarnings("javadoc")
@Before
public void setUp() {
    formatter = mock(FormatterService.class);
    setMock(formatter);
    when(formatter.formatTachoIcon()).thenReturn(MOCKED_URL);
}

/**
 * Remove the mocked instance from the class. It is important, because other tests will be confused with the mocked instance.
 * @throws Exception if the instance could not be accessible
 */
@After
public void resetSingleton() throws Exception {
   Field instance = FormatterService.class.getDeclaredField("instance");
   instance.setAccessible(true);
   instance.set(null, null);
}

/**
 * Set a mock to the {@link FormatterService} instance
 * Throws {@link RuntimeException} in case if reflection failed, see a {@link Field#set(Object, Object)} method description.
 * @param mock the mock to be inserted to a class
 */
private void setMock(FormatterService mock) {
    Field instance;
    try {
        instance = FormatterService.class.getDeclaredField("instance");
        instance.setAccessible(true);
        instance.set(instance, mock);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

/**
 * Test method for {@link com.example.DriverSnapshotHandler#getImageURL()}.
 */
@Test
public void testFormatterServiceIsCalled() {
    DriverSnapshotHandler handler = new DriverSnapshotHandler();
    String url = handler.getImageURL();

    verify(formatter, atLeastOnce()).formatTachoIcon();
    assertEquals(MOCKED_URL, url);
}

}

利用PowerMock to mockaloneton category (SingletonClassHelper) instance and non-static methods (nonStaticMethod) which is used in task.execute(.

    import static org.mockito.Mockito.when;

    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.mockito.InjectMocks;
    import org.mockito.Mock;
    import org.mockito.Mockito;
    import org.powermock.api.mockito.PowerMockito;
    import org.powermock.core.classloader.annotations.PrepareForTest;
    import org.powermock.modules.junit4.PowerMockRunner;

    @PrepareForTest({ SingletonClassHelper.class })
    @RunWith(PowerMockRunner.class)
    public class ClassToTest {

        @InjectMocks
        Task task;

        private static final String TEST_PAYLOAD = "data";
        private SingletonClassHelper singletonClassHelper;


        @Before
        public void setUp() {
            PowerMockito.mockStatic(SingletonClassHelper.class);
            singletonClassHelper = Mockito.mock(SingletonClassHelper.class);
            when(SingletonClassHelper.getInstance()).thenReturn(singletonClassHelper);
        }

        @Test
        public void test() {
            when(singletonClassHelper.nonStaticMethod(parameterA, parameterB, ...)).thenReturn(TEST_PAYLOAD);
            task.execute();
        }
    }

据我所知,无法扩大单一州的一个班级(超级楼层建筑商总是暗指的,单州建筑商是私人的)。 如果你想要 mo一个班子,你必须延长班级。 如你在此案中所看到的那样,这样做是不可能的。

下面是我不得不与一些不可改变的科特林单一州一起采用的解决办法,以测试这些解决办法。

附录

class MySingleton private constructor(
  {your dependencies}
) {
  companion object {
    @JvmStatic
    private var INSTANCE: MySingleton? = null

    @JvmStatic
    fun getInstance(): MySingleton {
      return INSTANCE ?: synchronized(this) {
        INSTANCE ?: MySingleton(
          {your dependencies}
        ).also {
          INSTANCE = it
        }
      }
    }
  }
}

您可以这样做。

@After
fun after() {
  val instance = MySingleton.Companion::class.memberProperties.find {
    it.name == "INSTANCE"
  }
  instance!!.isAccessible = true
  instance.javaField!!.set(null, null)
}

您仅需要将<条码>/条码>改为“条码”。

我认为,根据单一州对某类人员进行问题测试。

真正的问题是,在一个类别内(通常是在构造中)不采用单一吨(或任何其他类别)。

依赖性注射使你(除许多其他东西外)能够改变任何类别,无论是单一州还是其他类别,并且将模拟带入客户类别。 从那里可以检测到等级。

这使得难以检测单一吨<>自封! 由于其组成部分是建筑,在单一州内即时进行,没有注入。





相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...