Kotlin协程与Kotlin测试

Posted on 2024-08-16 14:32  Capterlliar  阅读(1)  评论(0编辑  收藏  举报

又上了一周班了(

1.

问题:需要发一堆HTTP请求,一个请求平均10s,所以需要并行,一个很正常的需求。于是学习了一下kotlin协程。

协程:建立在线程之上。一个线程可以运行成百上千的协程。可以使用调度器决定协程在哪个线程上运行。当一个协程挂起的时候,线程可以执行其他协程。

runBlocking:创建一个作用域,等里面所有协程都结束后出来。

async,launch:创建一个协程,async可以通过调用await获取结果,launch适用于不需要运行结果的场景。

Dispatcher:调度器。有的调度器,如Dispatcher.IO会创建一个线程池,然后在上面调度协程。

接下来写了一段代码:

runBlocking {
  files.map {
    file -> async {...//发HTTP请求}
  }.awaitAll()
}

运行了一下,发现还是串行的。因为发HTTP请求的操作是阻塞的,也就是说,等待结果期间协程并没有被挂起,也就不会执行其他协程,而是干等着。

于是有两个选择:一是使用异步HTTP请求,二是使用调度器。一的话会涉及到和Java的交互,比较麻烦,因此选择async(Dispatcher.IO)就可以了。

关于协程的其他部分这篇讲得非常好了。

然后超过目标服务器并行限制了

2.

修改了一些代码于是要改对应的test。已知添加了一个判断条件SystemProperties.get(),需要在测试里给定这个静态方法一个测试用的的值。

Mockito不能mock静态方法,于是有了ExtendedMockito,可以通过加载类时改字节码的方式mock静态方法。但这听起来不是一个test该干的事。一个解决方案是将该静态方法以参数的方式传递到类中,这样test的时候就可以把它替换掉,像这样:

class Person(val name: String, 
  var age: Int
  val height: () -> Int = { SystemProperties.get(...) }
)

然后test的时候这样:

var height: Int = 0

@Before
fun setUp() {
        person = Person("Alice",10) { height }
}

用的时候修改height的值即可。听上去有哪不对。kotlin的lambda函数用的是height的引用,所以是对的。

但是出现了新的问题。由于这段代码需要和Java交互,Java不直接支持默认参数。因此需要@JvmOverLoads让编译器生成两个构造函数,像这样:

class Person @JvmOverloads constructor()

顺带一提上面的class Person()也是构造函数,只是省略了constructor。

然后编译器就会生成带默认参数的和不带默认参数的两个构造函数,就可以直接用了。