改进此代码的方法
我正在尝试使用 Scalatest 为我的 java 应用程序编写一些测试代码。我想,由于 Scala 具有更易读的语法,因此会产生更易读的测试代码。
到目前为止,这就是我所做的:
package com.xyz import org.scalatest.FlatSpec import org.scalatest.matchers.ShouldMatchers import com.xyz.SecurityService import org.mockito.Mockito._ import org.scalatest.mock.MockitoSugar import org.mockito.Matchers._ import javax.servlet.jsp.tagext.Tag class CheckRoleTagSpec extends FlatSpec with ShouldMatchers with MockitoSugar { behavior of "CheckRole tag" it should "allow access when neither role nor root defined" in { val securityServiceMock = mock[SecurityService] val tag = new CheckRoleTag() tag.setSecurityService(securityServiceMock) tag.setGroup("group") tag.setPortal("portal") tag.setRoot(false) tag.setRole(null) tag.doStartTag should be(Tag.SKIP_BODY) } }
我对这段代码非常失望。这实际上与我需要用 Java 编写的东西是一样的。请帮助我使它更像 scala 和功能。
I am trying to write some test code for my java application using Scalatest. I figured, since Scala has so much more readable syntax it would result with more readable test code.
So far, this is what I managed:
package com.xyz import org.scalatest.FlatSpec import org.scalatest.matchers.ShouldMatchers import com.xyz.SecurityService import org.mockito.Mockito._ import org.scalatest.mock.MockitoSugar import org.mockito.Matchers._ import javax.servlet.jsp.tagext.Tag class CheckRoleTagSpec extends FlatSpec with ShouldMatchers with MockitoSugar { behavior of "CheckRole tag" it should "allow access when neither role nor root defined" in { val securityServiceMock = mock[SecurityService] val tag = new CheckRoleTag() tag.setSecurityService(securityServiceMock) tag.setGroup("group") tag.setPortal("portal") tag.setRoot(false) tag.setRole(null) tag.doStartTag should be(Tag.SKIP_BODY) } }
I am quite dissapointed with this code. It's practically the same thing I would need to write in Java. Please help me make it more scala-like and functional.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您无法通过重写测试来修复丑陋的测试。您只能通过重新设计正在测试的 API 来修复它。
嗯,从技术上来说,如果你真的很努力,非常邪恶,非常愚蠢,喝醉了或者非常累,那么有可能为好的 API 编写丑陋的测试。但是编写一个丑陋的测试需要努力,而且程序员很懒,所以不太可能有人会选择编写一个丑陋的测试。编写丑陋的测试几乎是不可能的:你插入一些东西,取出一些东西,检查你是否得到了你所期望的东西。就是这样。那里确实没有什么可丑化的。
测试只是使用 API,就像 API 用户使用它一样。它基本上是如何正确使用 API 的示例,而且几乎作为副作用,它碰巧检查 API 实际上是否正确实现。这就是为什么丑陋的测试是糟糕的 API 设计的良好指标,也是为什么测试驱动 API 设计是一件好事,即使您不进行 TDD。
在这种特殊情况下,我可以看到很多改进 API 的方法,尽管这些建议必然是不完整、肤浅和简单化的(更不用说可能是错误的),因为我对您的域一无所知:
setRoot
听起来像是在设置根。但是,除非false
是层次结构的根,否则我假设它的实际上设置是该标签是否是根。因此,它应该被命名为isRoot
或makeRoot
或setIsRoot
或类似的名称。setRoot
,假设我的猜测是正确的并且这设置了标签是否是根,那么默认值是错误的。根据“根”概念的定义,只能有一个根。因此,您强制用户setRoot(false)
每次指定,除了他们实际定义根的一次 。非根标签应该是默认值,并且您应该只强制为实际上是根的一个标签setRoot(true)
。setRole(null)
。严重地?您是否强制用户明确设置要取消设置的角色?为什么不简单地取消设置默认值呢?毕竟,测试被称为“...当角色和根都没有定义时”,那么为什么要定义它们呢?这样,测试基本上就变成了:
You cannot fix an ugly test by rewriting the test. You can only fix it by redesigning the API that is being tested.
Well, technically, it is possible to write ugly tests for good APIs if you try really hard, are very evil, very, stupid, very drunk or very tired. But writing an ugly test takes effort and programmers are lazy, so it is very unlikely that someone would write an ugly test by choice. It is almost impossible to write ugly tests: you stick something in, you get something out, you check whether you got what you expected. That's it. There's really nothing to uglify there.
A test just uses the API the same way a user of the API would use it. It's basically an example of how to use the API properly, that also, almost as a side-effect, happens to check that the API is actually implemented properly. That's why an ugly test is a good indicator for bad API design, and it's also why test-driving the API design is a good thing, even if you don't do TDD.
In this particular case, I can see quite a few ways to improve the API, although these suggestions are necessarily incomplete, shallow and simplistic (not to mention probably wrong), since I don't know anything about your domain:
setRoot
sounds like it is setting the root. But, unlessfalse
is the root of your hierarchy, I assume that what it is actually setting is whether or not this Tag is the root. So, it should rather be namedisRoot
ormakeRoot
orsetIsRoot
or something like that.setRoot
, assuming that my guess is correct and this sets whether or not the Tag is the root, then the default is the wrong way around. By the very definition of the concept of "root", there can only ever be one root. So, you are forcing your users to specifysetRoot(false)
every single time, except for that one time when they are actually defining a root. Non-root Tags should be the default, and you should only be forced tosetRoot(true)
for that one Tag which actually is the root.setRole(null)
. Seriously? You are forcing your users to explicitly set the role to be unset? Why not simply make unset the default? After all, the test is called "... when neither role nor root defined", so why define them?That way, the test basically becomes:
下面的代码创建了新的匿名类,但
doStartTag
按预期返回结果:The code below creates new anonymous class, but
doStartTag
returns result as expected:由于这个特定的测试只是在 Java 中实现的对象上调用一堆 setter,因此您无法做太多事情来使其更加简洁、功能性或 scalaish。您可以删除一些重复内容,例如
“我不确定在这种情况下是否真的值得”。
Since this particular test is just calling a bunch of setters on a object implemented in java, there's not a whole lot you can do to make it more succinct or functional or scalaish. You could remove some repetition with something like
I'm not sure whether it's really worth it in this case.