【问题标题】:How to get started with testing(jMock)如何开始测试(jMock)
【发布时间】:2010-05-25 13:41:47
【问题描述】:

我正在努力学习如何编写测试。我也在学习 Java,有人告诉我应该学习/使用/练习 jMock,我在网上找到了一些有助于一定程度的文章,例如:

http://www.theserverside.com/news/1365050/Using-JMock-in-Test-Driven-Development

http://jeantessier.com/SoftwareEngineering/Mocking.html#jMock

我发现的大多数文章都是关于测试驱动开发的,首先编写测试然后编写代码以使测试通过。我现在不是在寻找那个,我正在尝试使用 jMock 为已经存在的代码编写测试。

official documentation 至少可以说是模糊的,对我来说太难了。有没有人有更好的方法来学习这个。好书/链接/教程会对我有很大帮助。谢谢

编辑 - 更具体的问题:

http://jeantessier.com/SoftwareEngineering/Mocking.html#jMock - 来自这篇文章

试过这个来模拟这个简单的类:

import java.util.Map;
    public class Cache {
        private Map<Integer, String> underlyingStorage;
        public Cache(Map<Integer, String> underlyingStorage) {
            this.underlyingStorage = underlyingStorage;
        }
        public String get(int key) {
            return underlyingStorage.get(key);
        }
        public void add(int key, String value) {
            underlyingStorage.put(key, value);
        }
        public void remove(int key) {
            underlyingStorage.remove(key);
        }
        public int size() {
            return underlyingStorage.size();
        }
        public void clear() {
            underlyingStorage.clear();
        }
    }

这是我尝试创建测试/模拟的方式:

public class CacheTest extends TestCase {

    private Mockery context;
    private Map mockMap;
    private Cache cache;

    @Override
    @Before
    public void setUp() {
        context = new Mockery() {
            {
                setImposteriser(ClassImposteriser.INSTANCE);
            }
        };

        mockMap = context.mock(Map.class);
        cache = new Cache(mockMap);
    }

    public void testCache() {
        context.checking(new Expectations() {{
            atLeast(1).of(mockMap).size(); 
            will(returnValue(int.class));
        }});

    }
}

它通过了测试,基本上什么都不做,我想要的是创建一个地图并检查它的大小,你知道工作一些变化试图抓住这一点。通过示例更好地理解,我还可以在这里测试什么或任何其他练习会对我有很大帮助。 tnx

【问题讨论】:

  • 不是答案,但是:我建议在研究模拟之前学习如何编写测试。模拟是测试中的高级主题,您应该先掌握基础知识。
  • @Arne 你能给我具体的答案吗?什么被认为是基础知识?我是一个快速学习者,并不是说我比其他人更聪明只是我渴望学习并且有很多东西时间在我手上。因此,如果一件事变得无聊,我可以继续进行另一件简单/高级的事情,这并不重要。 tnx
  • 您可以在没有模拟框架的情况下编写测试。只需使用 JUnit 来编写您的测试。如果您正在流畅地测试您的代码,然后遇到一个没有模拟就无法掌握的情况,请尝试模拟框架。对模拟的需求应该是例外,而不是规则。

标签: java unit-testing testing mocking jmock


【解决方案1】:

这是一个关于使用 JUnit 和 EasyMock(我个人觉得比 JMock 更容易使用的模拟库)的教程:http://www.michaelminella.com/testing/unit-testing-with-junit-and-easymock.html

即使您 100% 致力于使用 JMock,两者之间的概念也是相同的,这应该有助于您更好地理解它们。

模拟的目的是,当您测试依赖于BC 的类A 时,您对A 的测试使用BC 的模拟版本能够指定它们的确切行为,而不是在您对A 的测试中使用BC 的实际实现。否则,您不仅要测试 A 的单个单元,还要隐式测试 BC

【讨论】:

  • 你能/你能模拟构造函数吗,因为它们不是我仍在努力掌握一切的方法。
  • 一些库支持模拟类,而不仅仅是接口(EasyMock 3.0 声称这一点),但我对它不是很熟悉。当你的类通过依赖 interface 而不是 concrete class 来表达相互依赖时,Mocking 会大放异彩。
【解决方案2】:

作为 JMock 的作者,在您对 TDD 有一些经验之前,我不会开始使用该技术。只需从基础开始并让它发挥作用。一旦您开始在规模和扩展设计方面遇到困难,请回到该技术。

Dave Astels 的书仍然是一本很好的介绍书,而且我认为那一代人中唯一一本很好地解释了 mock 的书。之后,您可能会(咳咳)考虑我们的“以测试为指导的不断发展的面向对象软件”

如果有人告诉你这是为了加快对文件系统的测试,请打折扣。

【讨论】:

    【解决方案3】:

    你不需要真正的模拟来测试这个类,因为它唯一的合作者是一个你可以直接使用的 Map。此外,您的班级实际上并没有做任何事情(委托除外),这就是为什么您觉得自己没有进行太多测试的原因。

    一个直接的测试可能是(我假设您使用的是 JUnit 4 - 您的代码是 JUnit 3 和 4 的奇怪混合

    @Test
    public void sizeIs0WhenEmpty()
    {
      Map<Integer, String> map = Collections.emptyMap();
      Cache cache = new Cache(map)
      assertEquals(0, cache.size());
    }
    

    使用 mock 会是(假设 mock 代码是正确的——我不使用 JMock)

    @Test
    public void sizeIs0WhenEmpty()
    {
      context.checking(new Expectations() {{
                       atLeast(1).of(mockMap).size(); 
                       will(returnValue(0));
                       }});
      assertEquals(0, cache.size());
    }
    

    在这两种情况下,您都可以通过将地图设置为具有要测试的属性来设置系统,然后检查缓存是否具有相同的属性(因为它是直接委托)。

    我建议您在继续之前阅读about JUnit

    【讨论】:

      【解决方案4】:

      我不知道你在学习在测试中使用模拟对象的道路上走了多远,所以我会写一个简短的描述,然后为你指明可能对你有帮助的文章的方向。模拟对象在单元测试中用于替换难以创建或难以进入您希望它们进行测试的状态的外部依赖项。现有的各种模拟框架为您提供了创建“假”对象来代替这些依赖项的机制。这些模拟对象将跟踪从您的代码传入它们的调用,并允许您稍后对这些交互进行断言。有一篇众所周知的文章关于模拟对象以及它们如何与“存根”相关,“存根”是另一种用于简化外部依赖项的常见测试策略。它由 Martin Fowler 编写,可在此处找到:

      http://martinfowler.com/articles/mocksArentStubs.html

      【讨论】:

      • 你能/你能模拟构造函数吗,因为它们不是我仍在努力掌握一切的方法。
      • 不,模拟是在类级别完成的,因此模拟框架将为您处理创建“代理”(即模拟)对象。请记住,这个对象并没有实现它所模拟的对象的行为。它的目的是跟踪与它的交互,并让您验证这些交互是否按照您的预期发生。
      • 感谢您的解释,我该如何测试其中一些方法?
      • 我不会再推荐模拟不是存根文章了。从那时起,我们的理解有了很大的提高。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-07
      • 1970-01-01
      • 1970-01-01
      • 2010-11-20
      • 1970-01-01
      相关资源
      最近更新 更多