简体   繁体   English

如何调用指示应该在实例上调用什么方法的传递参数

[英]How to call pass parameter that indicates what method should be called on instance

In me tests, i have many thing like:在我的测试中,我有很多类似的东西:

try{
  someInstance.someMethod(argument)
}catch(Exception e){
  // assert exception message
}

and i would like to create method for this, howerver how?我想为此创建方法,但是如何? How do i pass method that should be invoked on specific isntance?我如何传递应该在特定实例上调用的方法?

i tried我试过了

private <String,R> void  runCommandWithExpectedError(Function<String,R> fnc, String argument, String errorMessage){
    try {
        fnc.apply(argument);
    } catch (Exception e) {
        Assert.assertThat(e.getMessage(), Matchers.equalTo(errorMessage));
    }
}

However it complains that non static method cannot be refferenced from a static context.但是它抱怨不能从 static 上下文中引用非 static 方法。 when calling it like像这样称呼它时

runCommandWithExpectedError(ChannelSftp::rm,"path","No such file or directory");

Also there is no way the method knows what instance it should invoke the method on, is something like that possible?此外,该方法无法知道它应该在哪个实例上调用该方法,这样可能吗?

Thanks!谢谢!

General statement一般性发言

I wouldn't do this to simplify my unit tests.我不会这样做来简化我的单元测试。 Unit tests are supposed to test each component of the code and should be easy to read and modify.单元测试应该测试代码的每个组件,并且应该易于阅读和修改。 Keeping them like that, even if they sound repetitive, it is how your code works and I would prefer to have a simple test which looks like all the other but shows easily what it does.让它们保持这样,即使它们听起来重复,这就是你的代码的工作方式,我希望有一个简单的测试,它看起来像所有其他的,但很容易显示它的作用。

Visitor pattern访客模式

If you really want to go that way, this is something that can be done using the Visitor Design Pattern .如果你真的想要 go 那样,这可以使用访问者设计模式来完成。

Imagine you have two classes like this:想象一下,你有两个这样的类:

public class Class1 {
    public int method1(String string) {
        return string.contains("something") ? 2 : 3;
    }
}

public class Class2 {
    public double method2(String string) {
        return string.contains("something") ? 3.0 : 4.0;
    }
}

Your tests look something like this:您的测试如下所示:

@Test
public void test1() {
    Class1 class1 = new Class1();
    int result = class1.method1("something");
    //...assertions
}

@Test
public void test2() {
    Class2 class2 = new Class2();
    double result = class2.method2("else");
    //...assertions
}

If my understanding is correct, you rather want a single method testing the call to the method and eventually catching the exception to test its message.如果我的理解是正确的,您宁愿使用单个方法测试对该方法的调用并最终捕获异常以测试其消息。


First, you create a Visitor interface for each type you want to test:首先,为要测试的每种类型创建一个Visitor界面:

public interface Visitor {
    int visit(Class1 class1, String argument);
    double visit(Class2 class2, String argument);
}

Then, you create an interface Visitable that accepts a Visitor type:然后,您创建一个接受Visitable类型的Visitor接口:

public interface Visitable {
    public void accept(Visitor visitor, String argument);
}

Once you did this, you should make the classes you want to test implementing the Visitable interface (basically making them "visitable" by a "visitor"):一旦你这样做了,你应该让你想要测试的类实现Visitable接口(基本上让它们被“访问者”“访问”):

public class Class1 implements Visitable {
    public int method1(String string) {
        return string.contains("something") ? 2 : 3;
    }

    @Override
    public void accept(Visitor visitor, String argument) {
        visitor.visit(this, argument);
    }
}

public class Class2 implements Visitable {
    public double method2(String string) {
        return string.contains("something") ? 3.0 : 4.0;
    }

    @Override
    public void accept(Visitor visitor, String argument) {
        visitor.visit(this, argument);
    }
} 

Now, you can create a TestVisitor class which implements the Visitor interface and performs the action you wish:现在,您可以创建一个TestVisitor class ,它实现了Visitor接口并执行您希望的操作:

public class TestVisitor implements Visitor {

    @Override
    public int visit(Class1 class1, String argument) {
        return class1.method1(argument);
    }

    @Override
    public double visit(Class2 class2, String argument) {
        return class2.method2(argument);
    }
}

So, it is possible to refactor your unit tests with a single test performing the operation:因此,可以通过执行操作的单个测试来重构您的单元测试:

private final Visitor TEST_VISITOR = new TestVisitor();

private void sharedTestMethod(Visitable instance, String argument) {
    instance.accept(TEST_VISITOR, argument);
}

And your tests simply create the instance then call the sharedTestMethod :您的测试只需创建实例然后调用sharedTestMethod

@Test
public void test1() {
    Class1 class1 = new Class1();
    sharedTestMethod(class1, "something");
}

@Test
public void test2() {
    Class2 class2 = new Class2();
    sharedTestMethod(class2, "else");
}

Let's not forget the downsides (quoted by the link above):我们不要忘记缺点(由上面的链接引用):

Watch Out for the Downsides The arguments and return types for the visiting methods needs to be known in advance, so the Visitor pattern is not good for situtations where these visited classes are subject to change.注意缺点arguments 和访问方法的返回类型需要提前知道,因此访问者模式不适用于这些访问的类可能发生变化的情况。 Every time a new type of Element is added, every Visitor derived class must be amended.每次添加新类型的元素时,必须修改每个访问者派生的 class。 Also, it can be difficult to refactor the Visitor pattern into code that wasn't already designed with the pattern in mind.此外,将访问者模式重构为尚未考虑到该模式的代码可能很困难。 And, when you do add your Visitor code, it can look obscure.而且,当您添加访问者代码时,它可能看起来晦涩难懂。 The Visitor is powerful, but you should make sure to use it only when necessary.访客功能强大,但您应确保仅在必要时使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM