Android 上的测试用例继承

Inheritance of TestCases on Android

我想知道在 Android 上分 class 测试用例是否是个好习惯。我的意思是,我需要测试很多 Parcelable 个对象,我可以创建一个像 GenerericParcelableAndroidTestCase 这样的 class 来测试所有这些对象。

我在实现它时也遇到了问题,我有这样的事情:

public class GenericParcelableTest extends AndroidTestCase {

    private Parcelable p = null;

    GenericParcelableTest(Parcelable p) {
        this.p = p;
    }

    public void testDescribeContents() throws Exception {
        assertEquals(0, p.describeContents());

    }
}

还有:

public class AttachmentTest extends GenericParcelableTest {

    public AttachmentTest() {
        super(new Attachment());
    }
}

Attachment 当然实现 Parcelable

它 returns 我这个错误:

junit.framework.AssertionFailedError: Class GenericParcelableTest has no public constructor TestCase(String name) or TestCase()

我的意思是,我知道我没有创建空构造函数,但我为什么需要一个?

一般来说,这种方法是否存在一些已知问题?如果不是,为什么互联网上关于这个主题的文章很少(实际上 some 甚至说这不是一个好主意)。

junit.framework.AssertionFailedError: Class GenericParcelableTest has no public constructor TestCase(String name) or TestCase()

您收到此错误是因为 JUnit 需要能够构建您的测试实例 class。它只知道如何使用无参数或单字符串构造函数来做到这一点。

您不应在构造函数中执行初始化,而应将其放在 setUp() 方法中。这将允许您使用默认构造函数,同时仍然在调用测试方法之前初始化对象。

在向新的团队成员介绍单元测试时,我经常进行这种对话。我解释它的方式是声明你的测试是第一个class你的代码库的公民(没有双关语意),他们容易受到与其他任何人相同的技术债务的影响您的代码库的一部分,并且具有与 运行 时间代码同等(也许更高?!)的重要性。

有了这种心态,问题就开始有了答案;如果从 OO 的角度来看使用继承是有意义的(即你的 subclass 是一个 insert name of test superclass) 然后 subclass 离开。然而,就像任何对继承的滥用一样,要小心......当你添加一个不依赖于超级class行为的测试用例时,你可能会有代码味道。

在这种情况下,很可能(可能是 90% 的时间?)这是被测试代码中的关注点分离问题,即被测试的 "unit" 实际上不是(一个) 单元,但具有组合行为。重构该代码来做一件事将是让您的 super-class 测试用例继续存在的好方法。然而,像鹰一样观看这个超级 class 测试用例......当你看到布尔值被添加到 "allow that similar but not the same" 测试用例的签名到你曾经未受污染的超级 class 下的 运行 的那一刻] 那么你就有问题了,技术债务问题与你的运行时间码没有什么不同。

最后检查 AndroidTestCase 依赖于 Activity 上下文,因此最好将其描述为集成测试,它通常具有样板 super-class 测试行为。在这种情况下,尝试将 superclass 的焦点缩小到被测试的用例......即extends LoginUseCaseextends LoginScenario 以更好地 "bucket" 那些 subclass 是第一个实例。这将有助于指导 would be 扩展者是否应该将其用于非登录场景。希望对话会随之而来,避免技术债务积累!

关于您的错误,在 JUnit3 中按照@Allen 的建议进行操作,如果使用 Robolectric 之类的内容迁移到 JUnit4,则使用 Rules 以及 @BeforeClass 进行探索。

个人笔记

我只觉得有必要为模拟 API 端点的伪单元测试编写测试超级 classes(如果您熟悉的话,类似于 MockWebServer产品)和 DAO 集成测试,从而在每个测试的生命周期内启动和拆除内存中的数据库(警告 - 缓慢(但有用)的测试!)