当前位置: 首页 > 知识库问答 >
问题:

用匕首破解MockK类验证

耿和韵
2023-03-14

预期:测试Dagger使用空构造函数创建了存储库类

问题:使用mockkconstructorconfirmverified创建存储库类时使用Dagger依赖注入来创建Mockk验证正在中断。

使用Dagger的Android构造函数模式实现存储库时,需要一个带有@inject的空构造函数以便Dagger应用程序组件AppComponent.kt知道创建类。

confirmverified被注释掉时,测试通过。在实现confirmverified时,将调用和跟踪来自先前测试的方法,从而导致验证失败。

在单元测试中,mockkobject用于模拟SomeRepository.kt对象,因为它是在Kotlin中手动创建的对象。

SomeRepository.kt

object SomeRepository {
    someMethod(...){...}  
}
@ExtendWith(SomeTestExtension::class)
class SomeParamUnitTest(val testDispatcher: TestCoroutineDispatcher) {

    private fun TestLoad() = teedLoadTestCases()
    private lateinit var someViewModel: SomeViewModel

    @BeforeAll
    fun beforeAll() {
        mockkObject(SomeRepository)
        ...
    }

    @AfterAll
    fun afterAll() {
        unmockkAll()
    }

    @ParameterizedTest
    @MethodSource("TestLoad")
    fun `Feed Load`(test: FeedLoadTest) = testDispatcher.runBlockingTest {
        mockComponents(test)
        someViewModel = SomeViewModel(...)
        assertContentList(...) // Working as expected.
        verifyTests(test)
    }

    private fun mockComponents(test: FeedLoadTest) {
        ...
        coEvery {
            SomeRepository.someMethod(test.isRealtime, any())
        } returns mockSomeMethod(test.mockFeedList, test.status)
        ...
    }

    private fun verifyTests(test: FeedLoadTest) {
        coVerify {
            SomeRepository.someMethod(test.isRealtime, any())
        }
        confirmVerified(SomeRepository)
    }
}
class App : Application() {
    val appComponent = DaggerAppComponent.create()
    ...
}
@Singleton
@Component
interface AppComponent {
    fun someRepository(): SomeRepository

    // The repository is injected inside of a fragment, then passed as a parameter into the ViewModel.
    fun inject(someFragment: SomeFragment)
}
@Singleton
class SomeRepository @Inject constructor() {
    someMethod(...){...}  
}

Someparamunittest.kt

@ExtendWith(SomeTestExtension::class)
class SomeParamUnitTest(val testDispatcher: TestCoroutineDispatcher) {

    private fun TestLoad() = teedLoadTestCases()
    private lateinit var repository: SomeRepository
    private lateinit var someViewModel: SomeViewModel

    @BeforeAll
    fun beforeAll() {
        mockkConstructor(SomeRepository::class)
        ...
    }

    @AfterAll
    fun afterAll() {
        unmockkAll()
    }

    @ParameterizedTest
    @MethodSource("TestLoad")
    fun `Feed Load`(test: FeedLoadTest) = testDispatcher.runBlockingTest {
        repository = SomeRepository()
        mockComponents(test)
        someViewModel = SomeViewModel(...)
        assertContentList(...) // Working as expected.
        verifyTests(test)
    }

    private fun mockComponents(test: FeedLoadTest) {
        ...
        coEvery {
            anyConstructed<SomeRepository>().someMethod(test.isRealtime, any())
        } returns mockSomeMethod(test.mockFeedList, test.status)
        ...
    }

    private fun verifyTests(test: FeedLoadTest) {
        coVerify {
            anyConstructed<SomeRepository>().someMethod(test.isRealtime, any())
        }
        confirmVerified(repository)
    }
}

对于运行的每个参数化测试,验证的和记录的调用计数都在累积增加。

java.lang.AssertionError:验证确认失败

这似乎是一个改进,因为已验证和记录的测试不再像以前那样累加每个参数化测试轮。而是找不到正确的方法签名。

java.lang.AssertionError:验证确认失败

已验证的呼叫计数:0已记录的呼叫计数:2

ClearConstructorMockkUnmockkConstructor分别进行了测试,并收到了与尝试的解决方案#2相同的失败消息。

共有1个答案

丌官信厚
2023-03-14
@ExtendWith(SomeTestExtension::class)
class SomeParamUnitTest(val testDispatcher: TestCoroutineDispatcher) {

    private fun TestLoad() = teedLoadTestCases()
    private val repository = mockkClass(SomeRepository::class)
    private lateinit var someViewModel: SomeViewModel

    @AfterAll
    fun afterAll() {
        unmockkAll()
    }

    @ParameterizedTest
    @MethodSource("TestLoad")
    fun `Feed Load`(test: FeedLoadTest) = testDispatcher.runBlockingTest {
        mockComponents(test)
        someViewModel = SomeViewModel(...)
        assertContentList(...) // Working as expected.
        verifyTests(test)
    }

    private fun mockComponents(test: FeedLoadTest) {
        ...
        coEvery {
            repository.someMethod(test.isRealtime, any())
        } returns mockSomeMethod(test.mockFeedList, test.status)
        ...
    }

    private fun verifyTests(test: FeedLoadTest) {
        coVerify {
            repository.someMethod(test.isRealtime, any())
        }
        confirmVerified(repository)
    }
}
 类似资料:
  • 我正在使用Dagger 2,在为我的类实现测试时,模块中的generate singleton providers存在一些问题。 所以我有两个问题。 > 我不能使用构造函数注入,因为有一个默认的构造函数。如何从测试模块中获取Foo? 在和中,如何确保在运行每个测试时创建的新实例? 谢谢

  • 这很好,但是如果我使用全局组件甚至子组件中的一个模块,那么应该传入上下文。因此,这意味着如果我用匕首注入演示器,它将被绑定到ApplicationContext。这使得作为JUnit进行测试变得困难。Android代码不应该在演示器中。 所以我想问的是,最好的做法是只在活动、片段、广播接收器和服务中使用匕首吗?就mvp架构而言,这就是。另一个解决方案是设计另一个dagger组件,但不是与appco

  • 我在android项目中使用Dagger2我有两个作用域:ActivityScope和FragmentScope我读了一些示例代码,他们说定义并使用ActivityScope,所以对象将在activity lifecycle中销毁。因为活动和片段有不同的生命周期,所以我们应该有两个作用域。 我的问题是:我是否需要做一些事情让代码知道,当我使用ActivityScope时,对象应该随活动生命周期一起

  • 我正在尝试通过修改MVP应用程序Belajar应用程序在MVVM架构中应用DaggerApplicationComponent,但是我刚刚收到未解决的引用:DaggerApplicationComponent的错误。Kotlin kapt 已被应用,我尝试重建项目,但我从应用程序组件收到错误:C:\Users\3\AndroidStudioProjects\belajar3 - Copy (3)\

  • Dagger 2即将面世,但可用的示例甚至无法立即编译,文档是Dagger 1的复制粘贴替换。 有没有人有一个在谷歌的Dagger 2上运行的正确应用程序的例子?

  • 我找到了静态编程语言Lazy对象的答案,在这里使用:静态编程语言:检查Lazy val是否已初始化 但看起来像匕首。Lazy没有相同的公共方法。 这就是我如何懒洋洋地使用Dagger注射: 如何在不调用someService的情况下检查someService是否已初始化。get()哪个将初始化它?除了引入布尔标志并自己跟踪它之外。。 谢谢