Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 单元测试的适当方法封装_Java_Unit Testing_Methods_Junit_Encapsulation - Fatal编程技术网

Java 单元测试的适当方法封装

Java 单元测试的适当方法封装,java,unit-testing,methods,junit,encapsulation,Java,Unit Testing,Methods,Junit,Encapsulation,我的类包含14个私有方法和1个公共方法。public方法通过其他私有方法直接或间接调用所有私有方法 public方法还可以调用查询数据库的DAO。 我为这个班写了一个单元测试。因为您不能为私有方法编写单元测试,所以我将所有私有方法都更改为默认访问,并为它们编写了单元测试 有人告诉我,我不应该仅仅为了测试而更改封装。但是我的公共方法调用DAO并从调用中获取其数据。即使我要为public方法编写一个测试,我也认为它会非常漫长和复杂 我应该如何处理这个问题。一方面,我必须为访问DAO的公共方法编写一个

我的类包含
14个私有方法
1个公共方法
。public方法通过其他私有方法直接或间接调用所有私有方法

public方法还可以调用查询数据库的
DAO
。 我为这个班写了一个单元测试。因为您不能为私有方法编写单元测试,所以我将所有私有方法都更改为默认访问,并为它们编写了单元测试

有人告诉我,我不应该仅仅为了测试而更改封装。但是我的公共方法调用DAO并从调用中获取其数据。即使我要为public方法编写一个测试,我也认为它会非常漫长和复杂

我应该如何处理这个问题。一方面,我必须为访问DAO的公共方法编写一个非常复杂的测试,另一方面,改变方法的访问级别,为它们编写简短的测试方法。我该怎么办


如果您有任何建议,我们将不胜感激。

您在这里似乎有两个问题:

  • 如何测试私有方法(假设在Java中):

    我想看看这个问题:

    我个人喜欢这样的回答:

    测试私有方法的最佳方法是通过另一个公共方法。如果无法执行此操作,则以下条件之一为真:

  • 私有方法是死代码
  • 您正在测试的类附近有一种设计气味
  • 您尝试测试的方法不应是私有的
  • 如何打破DAO的依赖性

    您可以尝试使用来摆脱对DAO的依赖。然后您可以模拟DAO并将其注入测试用例中。 好处是它真正成为一个单元测试,而不是一个集成测试


  • 纯粹主义者会告诉你,私有方法可以被提取到另一个提供可访问方法的助手类,他们可能是对的


    但是,如果将这些实用程序方法保留在类中是有意义的,如果该类不是公共API的一部分,并且不打算进行子类化(例如,它可能是final),我认为将其一些私有方法包保护或保护没有任何问题。特别是如果记录了这种非私有可见性,例如使用Guava注释
    @VisibleForTesting

    如果它很复杂,可能是因为您的类有多个职责。通常,当您有私有方法来做不同的事情时,您可以有不同的类和公共方法来为您做这些事情。你的课程将变得更容易阅读,更容易测试,你将把责任分开。14私有方法通常表示这类事情:P

    例如,您可以有如下内容

    public class LeFooService {
        private final OtherServiceForConversion barService;
        private final FooDao fooDao;
    
        public LeeFooService(FooDao dao, OtherServiceForConversion barService) {
            this.barService = barService;
            this.fooDao = dao;
        }
    
        public void createAsFoo(Bar bar) throws ConversionException {
            Foo foo = convert(bar);
    
            fooDao.create(foo);
        }
    
        private Foo convert(Bar bar) {
            // lots of conversion stuff, services calling D:
        }
    }
    
    ....
    @Test
    public void shouldHaveConvertedFooCorrectly() {
         // given
         Bar bar = mock(Bar.class);
    
         // when
         fooService.createAsFoo(bar);
    
         // then
         verify(fooDao).create(argThat(fooIsConvertedCorrectly());
    }
    
    private ArgumentMatcher<Foo> fooIsConvertedCorrectly() {
         return new ArgumentMatcher<Foo>() { /*test stuff*/ };
    }
    ....
    
    为了正确测试,您必须测试转换是否正确完成。因为它是私有的,所以您必须捕获发送到
    FooDao
    foo
    ,并查看是否所有字段都设置正确。您可以使用捕获发送到
    fooDao
    的内容,然后测试转换。你的测试看起来像

    public class LeFooService {
        private final OtherServiceForConversion barService;
        private final FooDao fooDao;
    
        public LeeFooService(FooDao dao, OtherServiceForConversion barService) {
            this.barService = barService;
            this.fooDao = dao;
        }
    
        public void createAsFoo(Bar bar) throws ConversionException {
            Foo foo = convert(bar);
    
            fooDao.create(foo);
        }
    
        private Foo convert(Bar bar) {
            // lots of conversion stuff, services calling D:
        }
    }
    
    ....
    @Test
    public void shouldHaveConvertedFooCorrectly() {
         // given
         Bar bar = mock(Bar.class);
    
         // when
         fooService.createAsFoo(bar);
    
         // then
         verify(fooDao).create(argThat(fooIsConvertedCorrectly());
    }
    
    private ArgumentMatcher<Foo> fooIsConvertedCorrectly() {
         return new ArgumentMatcher<Foo>() { /*test stuff*/ };
    }
    ....
    
    您将能够测试对LeeFooService真正重要的内容:调用流。从
    Foo
    Bar
    的转换测试将由
    BarToFooConverter
    的单元测试负责。LeeFooService的一个示例测试是

    @RunWith(MockitoJUnitRunner.class)
    public class LeFooServiceTest {
         @Mock
         private FooDao fooDao;
         @Mock
         private BarToFooConverter converter;
         @InjectMocks
         private LeeFooService service;
    
         @Test(expected = ConversionException.class)
         public void shouldForwardConversionException() {
             // given 
             given(converter.convert(Mockito.any(Bar.class))
                .willThrown(ConversionException.class);
    
             // when
             service.createAsFoo(mock(Bar.class));
    
             // then should have thrown exception
         }
    
         @Test
         public void shouldCreateConvertedFooAtDatabase() {
             // given 
             Foo convertedFoo = mock(Foo.class);
             given(converter.convert(Mockito.any(Bar.class))
                .willReturn(convertedFoo); 
    
             // when
             service.createAsFoo(mock(Bar.class));
    
             // then
             verify(fooDao).create(convertedFoo);
         }
    }
    
    希望能有所帮助:)

    一些可能有用的链接:


    一个包含一个公共方法和14个私有方法的类几乎无法测试。在没有看到它的情况下,我愿意打赌,它是非常不可靠的。就像他说的那样;我和我的纯粹主义者同事会将大部分或所有私有方法提取到助手类中。原因是:

    • 易于测试
    • 易于重构
    • 易读
    • 易于重用
    不提取的原因: *很多!!班级 *提取需要时间 *有时,性能问题会妨碍“适当”设计的美观性

    在以下情况下,应始终考虑IMHO逻辑提取:

    • 私有方法
    • 大班(我通常会在 垂直滚动条显示在我的编辑器中(winow)
    • 内部循环 循环

    这里的关键词是单一责任(SRP)

    家长会告诉孩子:不要暴露你的隐私

    您不需要公开您的私有方法来测试它们。您可以获得类的100%测试覆盖率,包括那些私有方法,而无需公开它们

    问题在于,有些人认为单元测试中的“单元”是函数,而实际上是类

    例如:我有一个具有1个公共方法的类: bool CheckIfPalindrome(字符串字tocheck)

    在内部,我有私有方法来验证wordToCheck的长度,如果它为null,如果它为空,等等等等

    但作为测试人员,我不需要知道或关心开发人员如何组织(或将如何组织)内部代码。我正在测试接口的实现

    '如果单词是“Mike”,那么调用checkifpalindrom时,它应该返回false'

    '给定单词为“Mom”,当调用checkifpalindrom时,它应该返回true'

    '给定单词为“”,调用CheckIfPalindronme时,它应返回false'

    '如果单词为null,则调用CheckIfPalindronme时,它应该抛出一个错误'

    如果我涵盖了所有可能的输入和预期的输出,我将测试您的私有功能

    这是TDD/BDD的基础,如果没有它,TDD就不可能实现,因为在我们编写测试之前,我们必须等待并看看您决定如何组织代码

    TDD/BDD说写你的tes