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的公共方法编写一个非常复杂的测试,另一方面,改变方法的访问级别,为它们编写简短的测试方法。我该怎么办
如果您有任何建议,我们将不胜感激。您在这里似乎有两个问题:
纯粹主义者会告诉你,私有方法可以被提取到另一个提供可访问方法的助手类,他们可能是对的
但是,如果将这些实用程序方法保留在类中是有意义的,如果该类不是公共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个私有方法的类几乎无法测试。在没有看到它的情况下,我愿意打赌,它是非常不可靠的。就像他说的那样;我和我的纯粹主义者同事会将大部分或所有私有方法提取到助手类中。原因是:
- 易于测试
- 易于重构
- 易读
- 易于重用
- 私有方法
- 大班(我通常会在 垂直滚动条显示在我的编辑器中(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