单例测试和子类化

发布于 2024-11-28 01:36:43 字数 145 浏览 1 评论 0原文

我在使用 picocontainer 时看到了这个。他们说你必须避免单身人士。 因为单例模式使得类(以及可能依赖于它的所有其他类)几乎不可能可测试。子类化或为 Singleton 类创建模拟对象非常困难。

但如果您确实需要它,是否有解决测试和子类化问题的方法?

I saw this while using picocontainer. They say you have to avoid singletons.
because the Singleton pattern makes it almost impossible for the class (and possibly all other classes which depend on it) to be testable. It's very hard to subclass, or to create a mock object for a Singleton class.

But if you absolutely need it , Is there a workaround for the testing and subclassing issue ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

如若梦似彩虹 2024-12-05 01:36:43

使测试单例变得困难的是强制执行其单例性的代码(即 public static MySingleton getInstance() {...} 样板文件)。使用控制反转容器(例如 Picocontainer、Guice 或 Spring)可以消除对象的这种担忧,因此现在:

  • 可以实例化它,并让协作者在测试中插入它,而不会出现问题。

  • 调用单例的代码不必知道它正在查找什么类(它需要知道它是否必须调用静态方法)。

我认为 picocontainer 网站上的建议与此类似。他们告诉您的是,让我们的容器为您管理组件的范围,而不是将范围执行代码硬连接到它们中。

What makes it hard to test singletons is the code enforcing their singleton-ness (meaning the public static MySingleton getInstance() {...} boilerplate). Using an inversion-of-control container, like Picocontainer or Guice or Spring, removes that concern from the object, so now:

  • It can be instantiated and have collaborators plugged into it in tests without a problem.

  • The code calling a singleton doesn't have to know what class it is looking up (which it would need to know if it had to call a static method).

I interpret the advice on picocontainer's website as being similar to this. What they are telling you is, let our container manage the scope of your components for you, don't hard-wire the scope-enforcing code into them.

断舍离 2024-12-05 01:36:43

如果您必须有单例:

  1. 有一个描述每个单例的接口
  2. 从全局/单例访问您的单例 ServiceLocator
  3. 测试时切换ServiceLocator中注册的实例

示例:

interface IBankApi
{
   public void MakeDeposity(int accountNumber, int dollarAmount);
   // ...
}

public class RealBankApi : IBankApi { ... }

// startup code
serviceLocator.Register<IBankApi>(new RealBankApi());

// code using the API
serviceLocator.Resolve<IBankApi>().MakeDeposit(...);

// test code setup
class FakeBankApi : IBankApi { ... }
serviceLocator.Register<IBankApi>(new FakeBankApi());

If you must have singletons:

  1. Have an interface describing each singleton
  2. Access your singletons from a global/singleton ServiceLocator
  3. Switch the instances registered in the ServiceLocator during testing

Example:

interface IBankApi
{
   public void MakeDeposity(int accountNumber, int dollarAmount);
   // ...
}

public class RealBankApi : IBankApi { ... }

// startup code
serviceLocator.Register<IBankApi>(new RealBankApi());

// code using the API
serviceLocator.Resolve<IBankApi>().MakeDeposit(...);

// test code setup
class FakeBankApi : IBankApi { ... }
serviceLocator.Register<IBankApi>(new FakeBankApi());
花开雨落又逢春i 2024-12-05 01:36:43

由于其他原因,使用 IOC(控制反转)而不是首次使用时启动的单例也是有利的。

单例初始化可能会遭受(众所周知的)多线程问题,其中两个线程尝试同时第一次访问它。后续访问可能会正确同步,但第一次访问要困难得多。

我发现使用 IOC 的另一个巨大优势是初始化时可能发生错误。您不希望这种情况在“首次使用”时发生,您希望尽早知道此故障,并且当然以这种方式处理错误更容易。

最后,在测试方面,IOC提供了完美的模型来隔离组件,根据需要替换它们,并以更灵活的方式将不同的组合组合在一起,从而为单元测试和集成测试提供了完美的工具,以及良好的测试环境。回滚机制,实际上根本不需要恢复任何代码。

单例如此频繁使用的一般原因不是为了单一性,而是为了全局性。如果您的项目管理正确,您将拥有一个全局对象,所有其他对象都“注册”到该全局对象(因此您的 IOC 模型挂在它上面)并且可以在全局范围内使用,同时仍然是可配置的。

Using IOC (inversion of control) rather than singletons initiated at first use is advantageous for other reasons too.

Singleton-initialisation can suffer (famously) from multi-threading issues where two threads try to access it for the first time simultaneously. Subsequent access is likely to be correctly synchonised but the first one is much harder to do.

Another huge advantage I have found of using IOC is when an error may occur in initialisation. You do not want this to happen on "first use", you want to know of this failure at an early stage, and certainly it is easier to handle the error this way.

Finally, with regards to testing, IOC provides the perfect model to isolate components, substitute them as necessary and bring together different combinations in a more flexible way, thus providing the perfect harness for both unit-testing and integration testing, as well as a good rollback mechanism without actually having to revert any code at all.

The general reason singletons are so often used is not for the one-ness but for the global-ness. If your project is managed correctly you have a single global object to which all the others "register" (thus your IOC model hangs off it) and are available globally whilst still being configurable.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文