Java 使用理论时,如何在jUnit中获得条件执行?
我有一个抽象的测试用例,它使用Java 使用理论时,如何在jUnit中获得条件执行?,java,junit,Java,Junit,我有一个抽象的测试用例,它使用理论运行程序测试一个接口。接口的每个实现都有一个测试用例的具体实现,其中一个实现使用Postgres。我希望仅当连接到Postgres数据库的连接实际可用时才运行该测试用例,否则将被忽略 我不能使用假设,因为理论测试运行程序将失败,如果一个理论的所有数据点都不符合他们的假设 我正在测试一个ResourceStore,它本质上是一个简单的文件系统。它获取路径并返回资源对象,这些对象可能由文件系统或其他类似Postgres的东西支持。我使用理论来测试返回的资源是否遵循某
理论
运行程序测试一个接口。接口的每个实现都有一个测试用例的具体实现,其中一个实现使用Postgres。我希望仅当连接到Postgres数据库的连接实际可用时才运行该测试用例,否则将被忽略
我不能使用假设
,因为理论
测试运行程序将失败,如果一个理论的所有数据点都不符合他们的假设
我正在测试一个ResourceStore,它本质上是一个简单的文件系统。它获取路径并返回资源对象,这些对象可能由文件系统或其他类似Postgres的东西支持。我使用理论来测试返回的资源是否遵循某些规则,以便实现彼此一致
基类如下所示(导入和大多数特定测试)
基于文件系统的实现创建一个临时目录,用一些文件设置它,然后用路径(有些是现有的,有些不是)访问正在测试的存储
public class FileSystemResourceTheoryTest extends ResourceTheoryTest {
FileSystemResourceStore store;
@Rule
public TemporaryFolder folder= new TemporaryFolder();
@DataPoints
public static String[] testPaths() {
return new String[]{"FileA","FileB", "DirC", "DirC/FileD", "DirE", "UndefF", "DirC/UndefF", "DirE/UndefF", "DirE/UndefG/UndefH/UndefI"};
}
@Override
protected Resource getResource(String path) throws Exception{
return store.get(path);
}
@Before
public void setUp() throws Exception {
folder.newFile("FileA");
folder.newFile("FileB");
File c = folder.newFolder("DirC");
(new File(c, "FileD")).createNewFile();
folder.newFolder("DirE");
store = new FileSystemResourceStore(folder.getRoot());
}
}
基于JDBC的模块有另一个基于第一个的抽象测试用例,它使用TestSupport委托来抽象连接和设置测试环境时的方言差异。同样的支持类也用于其他非理论测试
public abstract class AbstractJDBCResourceTheoryTest extends ResourceTheoryTest {
DatabaseTestSupport support;
@DataPoints
public static String[] testPaths() {
return new String[]{"FileA","FileB", "DirC", "DirC/FileD", "DirE", "UndefF", "DirC/UndefF", "DirE/UndefF"/*, "DirE/UndefG/UndefH/UndefI"*/};
}
protected JDBCResourceStoreProperties mockConfig(boolean enabled, boolean init) {
JDBCResourceStoreProperties config = createMock(JDBCResourceStoreProperties.class);
expect(config.isInitDb()).andStubReturn(init);
expect(config.isEnabled()).andStubReturn(enabled);
expect(config.isImport()).andStubReturn(init);
support.stubConfig(config);
return config;
}
protected DataSource testDataSource() throws Exception {
return support.getDataSource();
}
public AbstractJDBCResourceTheoryTest() {
super();
}
protected void standardData() throws Exception {
support.initialize();
support.addFile("FileA", 0, "FileA Contents".getBytes());
support.addFile("FileB", 0, "FileB Contents".getBytes());
int c = support.addDir("DirC", 0);
support.addFile("FileD", c, "FileD Contents".getBytes());
support.addDir("DirE", 0);
}
Integer getInt(ResultSet rs, String column) throws Exception {
int i = rs.getInt(column);
if(rs.wasNull()) return null;
return i;
}
@After
public void cleanUp() throws Exception {
support.close();
}
}
Postgres测试用例只是插入Postgres测试支持模块,并使用它初始化测试框架和正在测试的资源存储。它当前连接到每个测试的每个数据点的数据库,尽管我计划修复它
public class PostgresJDBCResourceTheoryTest extends AbstractJDBCResourceTheoryTest {
JDBCResourceStore store;
@Override
protected Resource getResource(String path) throws Exception{
return store.get(path);
}
@Before
public void setUp() throws Exception {
support = new PostgresTestSupport();
standardData();
JDBCResourceStoreProperties config = mockConfig(true, false);
replay(config);
store = new JDBCResourceStore(support.getDataSource(), config);
}
}
还有一个H2实现,其测试方式与此相同,但使用内存中的H2数据库。我不知道您的代码是什么样子,我做了一系列假设,并创建了一个似乎支持您意图的示例
import org.junit.experimental.theories.*;
@org.junit.runner.RunWith(Theories.class)
public class TheoryTest {
// this is one possible way to store the setting:
private static ThreadLocal<Boolean> postgresConnected = new ThreadLocal<>();
static interface Under {}
static class Over implements Under {}
static class Through implements Under {}
static { postgresConnected.set(true); } // this logic belongs somewhere else
@DataPoints
public static Under[] underData() {
if (postgresConnected.get())
return new Under[] { new Over(), new Through() };
return new Under[] { new Over() };
}
@Theory
public void testUnder(Under under) {
System.out.println(under.getClass());
org.junit.Assert.assertNotNull(under);
}
}
import org.junit.experimental.Theory.*;
@org.junit.runner.RunWith(theory.class)
公共类理论测试{
//这是存储设置的一种可能方式:
private static ThreadLocal postgresConnected=new ThreadLocal();
{}下的静态接口
{}下实现上的静态类
通过{}下的实现的静态类
静态{postgresConnected.set(true);}//此逻辑属于其他地方
@数据点
[]underData()下的公共静态{
if(postgresConnected.get())
在[]{new Over(),new Through()}下返回new;
在[]{new Over()}下返回new;
}
@理论
公共无效测试下(下){
System.out.println(在.getClass()下);
org.junit.Assert.assertNotNull(在下);
}
}
如果这不符合您的需要,请发布更多详细信息,我会看看我能想出什么。一个解决方案是使用ThreadLocal 它是一种允许您设置特定线程变量的机制,在您的情况下,您可以使用ThreadLocal传递Postgres连接,并根据连接的存在情况知道是否运行特定测试
这篇文章包含了一个简单的例子,说明了如何使用鉴于您更新的问题,以下是您的错误之处:您试图使用
@DataPoints
,这些数据点是在@before
(设置)代码之前定义的。正如我在评论中所说,您正在与JUnit
体系结构作斗争@DataPoints
是静态定义的,但您的数据库连接是在每次测试之后定义的。如我的原始答案所示,@DataPoints
根据连接状态的不同而变化是(绝对?)必要的,这在您的代码示例中不会发生
不过,我有一个可行的解决办法。因为理论至少需要一个有效的数据点,所以我创建了一个始终有效的回退,并在没有连接时使用它。代码以相反的顺序发布,但确实编译并运行(当从问题中恢复剪报时)
公共类PostgresJDBCResourceTest扩展了AbstractJDBCResourceTheoryTest{
静态JDBCResourceStore;
受保护的资源getResource(字符串路径)引发异常{
如果(路径==“AlwaysValidResource”)
返回总是有效的;
返回store.get(路径);
}
@课前
public static void setUp()引发异常{
. . .
store=新的JDBCResourceStore(support.getDataSource(),config);
connect();
}
@下课
公共静态void拆卸(){
断开连接();
}
}
公共抽象类AbstractJDBCResourceTheoryTest扩展了ResourceTheoryTest{
private static ThreadLocal connected=new ThreadLocal();
@数据点
公共静态字符串[]testpath(){
if(connected.get()==null | |!connected.get())
返回新字符串[]{“AlwaysValidResource”};
返回新字符串[]{“FileA”、“FileB”、“DirC”、“DirC/field”、“DirE”、“undef”、“DirC/undef”、“DirE/undef”/*、“DirE/UndefG/UndefH/UndefI”*/};
}
静态void connect(){
已连接。设置(true);
}
静态无效断开连接(){
已连接。设置(false);
}
}
@RunWith(理论课)
公共抽象类ResourceTheoryTest{
公共静态最终资源始终有效=新的AlwaysValidResource();
. . .
}
谢谢,但我认为这不起作用,因为我有一个抽象测试用例类的多个子类用于不同的实现。有些是在独立的模块中,这些模块可能并不总是被构建的,当它们被构建时,Postgres实例可能不可用,但是其余的测试用例仍然需要运行。当我有更多的时间时,我会更新这个问题。是的,问题中的更多细节会有所帮助,因为我认为所有这些情况都可以处理。问题不在于是否存在与测试的Postgres连接,而在于何时关闭测试
import org.junit.experimental.theories.*;
@org.junit.runner.RunWith(Theories.class)
public class TheoryTest {
// this is one possible way to store the setting:
private static ThreadLocal<Boolean> postgresConnected = new ThreadLocal<>();
static interface Under {}
static class Over implements Under {}
static class Through implements Under {}
static { postgresConnected.set(true); } // this logic belongs somewhere else
@DataPoints
public static Under[] underData() {
if (postgresConnected.get())
return new Under[] { new Over(), new Through() };
return new Under[] { new Over() };
}
@Theory
public void testUnder(Under under) {
System.out.println(under.getClass());
org.junit.Assert.assertNotNull(under);
}
}
public class PostgresJDBCResourceTheoryTest extends AbstractJDBCResourceTheoryTest {
static JDBCResourceStore store;
protected Resource getResource(String path) throws Exception {
if (path == "AlwaysValidResource")
return ALWAYS_VALID;
return store.get(path);
}
@BeforeClass
public static void setUp() throws Exception {
. . .
store = new JDBCResourceStore(support.getDataSource(), config);
connect();
}
@AfterClass
public static void tearDown() {
disconnect();
}
}
public abstract class AbstractJDBCResourceTheoryTest extends ResourceTheoryTest {
private static ThreadLocal<Boolean> connected = new ThreadLocal<>();
@DataPoints
public static String[] testPaths() {
if (connected.get() == null || ! connected.get())
return new String[]{"AlwaysValidResource"};
return new String[]{"FileA", "FileB", "DirC", "DirC/FileD", "DirE", "UndefF", "DirC/UndefF", "DirE/UndefF"/*, "DirE/UndefG/UndefH/UndefI"*/};
}
static void connect() {
connected.set(true);
}
static void disconnect() {
connected.set(false);
}
}
@RunWith(Theories.class)
public abstract class ResourceTheoryTest {
public static final Resource ALWAYS_VALID = new AlwaysValidResource();
. . .
}