Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/317.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_Spring Boot_Junit - Fatal编程技术网

Java 如何编写非封装单元测试?

Java 如何编写非封装单元测试?,java,unit-testing,spring-boot,junit,Java,Unit Testing,Spring Boot,Junit,我有一个自动连接的变量 @Autowired private DocumentConfig documentConfig; 我想使用此配置对象的各种状态对DocumentService进行测试。我有什么选择?最好的选择是什么 第一个想法是: @Test public void save_failure() { documentConfig.setNameRequired(true); /* testing code goes here */ docume

我有一个自动连接的变量

@Autowired
private DocumentConfig documentConfig;
我想使用此配置对象的各种状态对DocumentService进行测试。我有什么选择?最好的选择是什么

第一个想法是:

@Test
public void save_failure() {
    documentConfig.setNameRequired(true);
    /*
    testing code goes here
    */
    documentConfig.setNameRequired(false);
}
但我想更确定的是,变量在测试后被重置,以避免干扰其他测试,确保只有这个测试在它是问题的根源时才会出错

我的新想法是:

@Before
public void after() { documentConfig.setNameRequired(true); }
@Test
public void save_failure() {
    /*
    testing code goes here
    */
}
@After
public void after() { documentConfig.setNameRequired(false); }
但是,这根本不起作用,因为在整个文件执行之前和之后,而不是在单个测试中执行。我不希望只为一次测试创建一个新文件

我现在已经达成妥协:

@Test
public void save_failure() {
    documentConfig.setNameRequired(true);
    /*
    testing code goes here
    */
}
@After
public void after() { documentConfig.setNameRequired(false); }
它似乎做了我想做的一切,但我有几个问题。 假设nameRequired开始为false,是否保证不会干扰其他测试?
我有什么办法可以说得更清楚些吗?无论是对我未来的自我还是对他人。

目前还不清楚您使用的是哪种测试框架。对于普通单元测试,通过setter或构造函数注入使值可注入。什么最适合你的具体情况


如果不止三个;-对于要注入的这些值,您可以考虑引入一个配置类来将所有这些值作为单个参数注入。

目前还不清楚,您使用的测试框架是什么。对于普通单元测试,通过setter或构造函数注入使值可注入。什么最适合你的具体情况


如果不止三个;-对于要注入的这些值,您可以考虑引入一个配置类来将所有这些值作为单个参数注入。

可以在每次测试之前创建它。类Smth

private DocumentConfig documentConfig;

@Before
public void createConfig() {
    documentConfig = new DocumentConfig(mockedParams);
}

您可以在每次测试之前创建它。类Smth

private DocumentConfig documentConfig;

@Before
public void createConfig() {
    documentConfig = new DocumentConfig(mockedParams);
}

一种常用的方法是设置一个虚拟DocumentConfig,并将其注入到带有@Before注释的setUp方法中,以便在每个测试中重置整个上下文,例如:

@Before
public void setUp() {
    this.documentConfig = new DocumentConfig();
    this.documentConfig.setNameRequired(false);
    this.service = new DocumentService(this.documentConfig);
}
ReflectionTestUtils.setField(this.service, "documentConfig", this.documentConfig);
@RunWith(MockitoJUnitRunner.class)
public class DocumentServiceTest {
    @InjectMocks
    private DocumentService documentService;
    @Mock
    private DocumentConfig documentConfig;

    @Test
    public void save_failure()  {
        when(this.documentConfig.isNameRequired()).thenReturn(true); 
        // TODO: Implement test
    }
}
在本例中,我设置了一个简单的对象,nameRequired为false。我可能会删除该语句,因为布尔字段默认为false

如果不使用构造函数注入,并且没有documentConfig的setter,则必须使用反射来注入字段,例如:

@Before
public void setUp() {
    this.documentConfig = new DocumentConfig();
    this.documentConfig.setNameRequired(false);
    this.service = new DocumentService(this.documentConfig);
}
ReflectionTestUtils.setField(this.service, "documentConfig", this.documentConfig);
@RunWith(MockitoJUnitRunner.class)
public class DocumentServiceTest {
    @InjectMocks
    private DocumentService documentService;
    @Mock
    private DocumentConfig documentConfig;

    @Test
    public void save_failure()  {
        when(this.documentConfig.isNameRequired()).thenReturn(true); 
        // TODO: Implement test
    }
}
在测试中,您现在可以编写如下内容:

@Test
public void save_failure() {
    this.documentConfig.setNameRequired(true);
    // TODO: Implement test
}
@Before
public void setUp() {
    // Use a static import for Mockito.mock()
    this.documentConfig = mock(DocumentConfig.class);
    this.service = new DocumentService(this.documentConfig);
}

@Test
public void save_failure()  {
    // Use a static import for Mockito.when()
    when(this.documentConfig.isNameRequired()).thenReturn(true); 
    // TODO: Implement test
}
或者,您可以模拟DocumentConfig,这样您就不必依赖它的实现来测试DocumentService。我假设您在DocumentService代码中的某个地方调用isNameRequired,因此您可以这样模拟它:

@Test
public void save_failure() {
    this.documentConfig.setNameRequired(true);
    // TODO: Implement test
}
@Before
public void setUp() {
    // Use a static import for Mockito.mock()
    this.documentConfig = mock(DocumentConfig.class);
    this.service = new DocumentService(this.documentConfig);
}

@Test
public void save_failure()  {
    // Use a static import for Mockito.when()
    when(this.documentConfig.isNameRequired()).thenReturn(true); 
    // TODO: Implement test
}
由于这种模拟/注入设置经常发生,Mockito也有自己的runner,允许您摆脱设置方法,例如:

@Before
public void setUp() {
    this.documentConfig = new DocumentConfig();
    this.documentConfig.setNameRequired(false);
    this.service = new DocumentService(this.documentConfig);
}
ReflectionTestUtils.setField(this.service, "documentConfig", this.documentConfig);
@RunWith(MockitoJUnitRunner.class)
public class DocumentServiceTest {
    @InjectMocks
    private DocumentService documentService;
    @Mock
    private DocumentConfig documentConfig;

    @Test
    public void save_failure()  {
        when(this.documentConfig.isNameRequired()).thenReturn(true); 
        // TODO: Implement test
    }
}

一种常用的方法是设置一个虚拟DocumentConfig,并将其注入到带有@Before注释的setUp方法中,以便在每个测试中重置整个上下文,例如:

@Before
public void setUp() {
    this.documentConfig = new DocumentConfig();
    this.documentConfig.setNameRequired(false);
    this.service = new DocumentService(this.documentConfig);
}
ReflectionTestUtils.setField(this.service, "documentConfig", this.documentConfig);
@RunWith(MockitoJUnitRunner.class)
public class DocumentServiceTest {
    @InjectMocks
    private DocumentService documentService;
    @Mock
    private DocumentConfig documentConfig;

    @Test
    public void save_failure()  {
        when(this.documentConfig.isNameRequired()).thenReturn(true); 
        // TODO: Implement test
    }
}
在本例中,我设置了一个简单的对象,nameRequired为false。我可能会删除该语句,因为布尔字段默认为false

如果不使用构造函数注入,并且没有documentConfig的setter,则必须使用反射来注入字段,例如:

@Before
public void setUp() {
    this.documentConfig = new DocumentConfig();
    this.documentConfig.setNameRequired(false);
    this.service = new DocumentService(this.documentConfig);
}
ReflectionTestUtils.setField(this.service, "documentConfig", this.documentConfig);
@RunWith(MockitoJUnitRunner.class)
public class DocumentServiceTest {
    @InjectMocks
    private DocumentService documentService;
    @Mock
    private DocumentConfig documentConfig;

    @Test
    public void save_failure()  {
        when(this.documentConfig.isNameRequired()).thenReturn(true); 
        // TODO: Implement test
    }
}
在测试中,您现在可以编写如下内容:

@Test
public void save_failure() {
    this.documentConfig.setNameRequired(true);
    // TODO: Implement test
}
@Before
public void setUp() {
    // Use a static import for Mockito.mock()
    this.documentConfig = mock(DocumentConfig.class);
    this.service = new DocumentService(this.documentConfig);
}

@Test
public void save_failure()  {
    // Use a static import for Mockito.when()
    when(this.documentConfig.isNameRequired()).thenReturn(true); 
    // TODO: Implement test
}
或者,您可以模拟DocumentConfig,这样您就不必依赖它的实现来测试DocumentService。我假设您在DocumentService代码中的某个地方调用isNameRequired,因此您可以这样模拟它:

@Test
public void save_failure() {
    this.documentConfig.setNameRequired(true);
    // TODO: Implement test
}
@Before
public void setUp() {
    // Use a static import for Mockito.mock()
    this.documentConfig = mock(DocumentConfig.class);
    this.service = new DocumentService(this.documentConfig);
}

@Test
public void save_failure()  {
    // Use a static import for Mockito.when()
    when(this.documentConfig.isNameRequired()).thenReturn(true); 
    // TODO: Implement test
}
由于这种模拟/注入设置经常发生,Mockito也有自己的runner,允许您摆脱设置方法,例如:

@Before
public void setUp() {
    this.documentConfig = new DocumentConfig();
    this.documentConfig.setNameRequired(false);
    this.service = new DocumentService(this.documentConfig);
}
ReflectionTestUtils.setField(this.service, "documentConfig", this.documentConfig);
@RunWith(MockitoJUnitRunner.class)
public class DocumentServiceTest {
    @InjectMocks
    private DocumentService documentService;
    @Mock
    private DocumentConfig documentConfig;

    @Test
    public void save_failure()  {
        when(this.documentConfig.isNameRequired()).thenReturn(true); 
        // TODO: Implement test
    }
}

你在测试什么?DocumentConfig,还是另一个依赖于DocumentConfig的类?如果是前者,请使用try/finally。如果是后者,则为mock DocumentConfig。您正在测试什么?DocumentConfig,还是另一个依赖于DocumentConfig的类?如果是前者,请使用try/finally。如果是后者,mock DocumentConfig.我似乎理解这个答案,我喜欢它。但“之后”会比“之前”好吗?毕竟,目标是始终保持配置重置,除了在特定测试中。有了这样的改变,这实际上与我自己的最终解决方案非常相似。编辑:然后我还需要在定义中分配变量,看起来。不管怎样,我不明白。这似乎没有将此文件中的documentConfig与DocumentService中的autowired documentConfig连接起来,DocumentService是这些测试和其他文件的主要对象。此外:我假设您指的是新的DocumentConfigmockedParams,对吗?我似乎理解这个答案,我喜欢它。但“之后”会比“之前”好吗?毕竟,目标是始终保持配置重置,除了在特定测试中。有了这样的变化,这实际上与我的
自己的最终解决方案。编辑:然后我还需要在定义中分配变量,看起来。不管怎样,我不明白。这似乎没有将此文件中的documentConfig与DocumentService中的autowired documentConfig连接起来,DocumentService是这些测试和其他文件的主要对象。此外:我假设您指的是新的DocumentConfigmockedParams,对吗?