如何防止 Spring 在测试中使用 @Configuration?
How to prevent Spring from using a @Configuration that's in a test?
我在 spring 配置 xml 文件中得到了这个,我想显式加载它,里面有这个:
<context:annotation-config/>
<context:component-scan base-package="my.path" />
我在测试中是这样加载的:
new ClassPathXmlApplicationContext(new String[]{"/beans.xml"})
问题是,显然此扫描能够看到嵌套在另一个测试中的 @Configuration
,因为此测试位于 base-package
下的包中。出于我的测试目的,这是不受欢迎的行为。有什么办法可以防止这种情况发生吗?我不会这样 component-scan
加载 @Configuration
类。
这个怎么样:
<context:component-scan base-package="my.path" >
<context:exclude-filter type="annotation"
expression="org.springframework.context.annotation.Configuration" />
</context:component-scan>
在使用 Spring 的测试中避免这种情况的 一般 方法是让测试加载其自己的上下文配置:
@RunWith(SpringJUnit4Runner.class)
@ContextConfiguration(locations={"classpath:/path/to/beans.xml"})
public class SpringDatabaseTest {
}
请注意,使用 IntelliJ 的组件扫描(非常准确),不再出现麻烦的配置:
接下来就是测试目标的问题了。您打算测试什么?你想假装接线正常并且你会取回数据吗?您要验证与有线 bean 的实际交互吗?
如果你想做前者,不要为此使用 Spring。 相反,请完整使用 Mockito。在这里和那里注入一把豆子但模拟掉其余的豆子是没有意义的;它会导致混乱和不一致的测试。
您必须将一些 setter 属性添加到您需要注入模拟的 classes 中,并自己初始化它们,但这可以在 init
中处理无论如何功能。
来自您链接的博客,这是 mocked-out 数据库测试的完整代码。
package mavensnapshot;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.verify;
@RunWith(MockitoJUnitRunner.class)
public class MockDatabaseTest {
@Mock
private Database mockRepo;
@InjectMocks
private Middle middle;
@Before
public void init() {
End end = new End();
end.setDatabase(mockRepo);
middle.setEnd(end);
}
@Test
public void testReplaceRepositoryWithMock() {
doNothing().when(mockRepo).save();
middle.useEnd();
verify(mockRepo).save();
}
}
如果你想做后者,绝对用Spring。没有别的办法,说白了。在这一点上,您现在必须验证与代码的完整交互,而不仅仅是像您可以使用 mock 做的那样。这也取决于您的设置方式;我宁愿每个 class 都有自己的测试,假设它下面的层工作正常,然后在最低层强制进行具体测试,并在最高层引入更完整的集成测试。
同一个项目,不同的测试方式:
package mavensnapshot;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:/beans.xml"})
public class SpringDatabaseTest {
@Autowired
private Middle middle;
@Test
public void testMiddle() {
middle.useEnd();
}
}
我在 spring 配置 xml 文件中得到了这个,我想显式加载它,里面有这个:
<context:annotation-config/>
<context:component-scan base-package="my.path" />
我在测试中是这样加载的:
new ClassPathXmlApplicationContext(new String[]{"/beans.xml"})
问题是,显然此扫描能够看到嵌套在另一个测试中的 @Configuration
,因为此测试位于 base-package
下的包中。出于我的测试目的,这是不受欢迎的行为。有什么办法可以防止这种情况发生吗?我不会这样 component-scan
加载 @Configuration
类。
这个怎么样:
<context:component-scan base-package="my.path" >
<context:exclude-filter type="annotation"
expression="org.springframework.context.annotation.Configuration" />
</context:component-scan>
在使用 Spring 的测试中避免这种情况的 一般 方法是让测试加载其自己的上下文配置:
@RunWith(SpringJUnit4Runner.class)
@ContextConfiguration(locations={"classpath:/path/to/beans.xml"})
public class SpringDatabaseTest {
}
请注意,使用 IntelliJ 的组件扫描(非常准确),不再出现麻烦的配置:
接下来就是测试目标的问题了。您打算测试什么?你想假装接线正常并且你会取回数据吗?您要验证与有线 bean 的实际交互吗?
如果你想做前者,不要为此使用 Spring。 相反,请完整使用 Mockito。在这里和那里注入一把豆子但模拟掉其余的豆子是没有意义的;它会导致混乱和不一致的测试。
您必须将一些 setter 属性添加到您需要注入模拟的 classes 中,并自己初始化它们,但这可以在 init
中处理无论如何功能。
来自您链接的博客,这是 mocked-out 数据库测试的完整代码。
package mavensnapshot;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.verify;
@RunWith(MockitoJUnitRunner.class)
public class MockDatabaseTest {
@Mock
private Database mockRepo;
@InjectMocks
private Middle middle;
@Before
public void init() {
End end = new End();
end.setDatabase(mockRepo);
middle.setEnd(end);
}
@Test
public void testReplaceRepositoryWithMock() {
doNothing().when(mockRepo).save();
middle.useEnd();
verify(mockRepo).save();
}
}
如果你想做后者,绝对用Spring。没有别的办法,说白了。在这一点上,您现在必须验证与代码的完整交互,而不仅仅是像您可以使用 mock 做的那样。这也取决于您的设置方式;我宁愿每个 class 都有自己的测试,假设它下面的层工作正常,然后在最低层强制进行具体测试,并在最高层引入更完整的集成测试。
同一个项目,不同的测试方式:
package mavensnapshot;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:/beans.xml"})
public class SpringDatabaseTest {
@Autowired
private Middle middle;
@Test
public void testMiddle() {
middle.useEnd();
}
}