改进此代码的方法

我正在尝试使用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编写的同样的东西。 请帮助我使它更具可伸缩性和功能性。


下面的代码创建新的匿名类,但doStartTag按预期返回结果:

...
(new CheckRoleTag{
   setSecurityService(mock[SecurityService])
   setGroup("group")
   setPortal("portal")
   setRoot(false)
   setRole(null)
} doStartTag) should be(Tag.SKIP_BODY)
...

你不能通过重写测试来修复一个丑陋的测试。 您只能通过重新设计正在测试的API来修复它。

嗯,从技术上讲,如果你努力尝试,非常邪恶,非常愚蠢,非常醉或者非常疲倦,那么可以为好的API编写难看的测试。 但是编写一个丑陋的测试需要努力,程序员是懒惰的,所以有人会选择写一个丑陋的测试是不太可能的。 要写难看的测试几乎是不可能的:你在里面插入东西,你得到一些东西,你检查你是否得到了你所期望的。 而已。 那里真的没有什么可以丑化的。

测试只是以API的用户使用API​​的相同方式使用API​​。 它基本上是一个如何正确使用API​​的例子,并且几乎作为一个副作用来检查API实际上是否被正确实现。 这就是为什么一个糟糕的测试对糟糕的API设计来说是一个很好的指标,这也是为什么测试驱动API设计是一件好事,即使你没有做TDD。

在这种特殊情况下,我可以看到很多改进API的方法,尽管这些建议必然是不完整,浅薄和简单的(更不用说可能是错误的),因为我对你的域名一无所知:

  • 更好的名称: setRoot听起来像是设置根。 但是,除非false是层次结构的根源,否则我认为它实际设置的是该标记是否为根。 所以,它应该被命名为isRootmakeRootsetIsRoot或类似的东西。
  • 更好的默认值:继续setRoot ,假设我的猜测是正确的,并且这设置标签是否是根,那么缺省是错误的。 根据“根”这个概念的定义,只能有一个根。 所以,你迫使你的用户每次都指定setRoot(false) ,除了那些实际定义一个根的时候。 非根标签应该是默认值,并且您应该只能强制setRoot(true)实际为根的那个Tag设置setRoot(true)
  • 更好的默认值,第二部分: setRole(null) 。 真的吗? 您迫使您的用户明确将角色设置为未设置? 为什么不简单地设置默认值? 毕竟,测试被称为“......既不是角色也不是根定义”,那么为什么要定义它们呢?
  • 流利的API / Builder模式:如果你确实需要构造无效的对象(但请参阅下一点),至少应使用类似Fluent API或Builder模式的东西。
  • 只构造有效对象:但实际上,对象在构建时应始终有效,完整且完全配置。 您不应该构造一个对象,然后对其进行配置。
  • 这样,测试基本上变成:

    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 tag = new CheckRoleTag(mock[SecurityService], "group", "portal")
    
        tag.doStartTag should be(Tag.SKIP_BODY)
      }
    }
    

    由于这个特定的测试只是在一个用java实现的对象上调用了一些setter,所以没有太多的工作可以使它更简洁,更实用或者更加简洁。 你可以用类似的东西删除一些重复

    it should "allow access when neither role nor root defined" in {
      val securityServiceMock = mock[SecurityService]
    
      val tag = new CheckRoleTag()
    
      locally { 
        import tag._
        setSecurityService(securityServiceMock)
        setGroup("group")
        setPortal("portal")
        setRoot(false)
        setRole(null)
      }
    
      tag.doStartTag should be(Tag.SKIP_BODY)
    }
    

    我不确定在这种情况下是否真的值得。

    链接地址: http://www.djcxy.com/p/65683.html

    上一篇: Ways to improve this code

    下一篇: How to add config transformations for a custom config file in Visual Studio?