模拟父类的受保护方法会产生“受保护的访问”错误

时间:2016-06-16 13:43:41

标签: java unit-testing mockito

我正在尝试使用mockito为“另存为”操作编写单元测试。该操作的一部分是制作并显示FileDialog,用户可以在其中输入要保存的文件。选择一个文件不是我可以自动化的东西,所以我想模拟FileDialog并模拟mockedFileDialog.getFiles()以返回我想要“保存”的文件。

问题是文件对话框是在我的“另存为”操作的父类中创建的。 when(..)似乎只适用于嘲讽,但嘲笑我要测试的课程会破坏练习的重点。然后我只测试是否调用方法,这不是很有用。我可以在测试中运行AbstractSaveAction.saveNet(..),但这样我无法确定保存操作是否真的有效 - 我只是测试是否有一种方法可以保存一些东西,但是我无法测试如果有一系列事件调用此函数。

以下测试将产生:

SaveActionTest.java:[60,24] getFileDialog(java.lang.String,java.lang.String) has protected access in application.AbstractSaveAction

测试此操作的正确方法是什么?

要测试的代码

public class SaveAsAction extends AbstractSaveAction {
    public SaveAsAction(Controller controller, View view) {
       super("", "", controller, view);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        saveAsNet();
    }
}
public abstract class AbstractSaveAction extends GuiAction {
    public AbstractSaveAction(..) {
        //...
    }


    protected final File saveAsFile(FileDialog fileDialog, String extension) {
        //...
    }


    protected final void saveAsNet() {
        FileDialog fileDialog = getFileDialog("Save the world", "xml");
        File file = saveAsFile(fileDialog, "xml");
        saveNet(file);
    }

    protected final void saveNet(File file) {
        try {
            controller.saveAsFile(file);
        } catch (TicklishPolarBearException e) {
            //Panic
        }
    }

    protected final FileDialog getFileDialog(String title, final String extension) {
        FileDialog fileDialog = new FileDialog(view, title, FileDialog.SAVE);
        fileDialog.setFile("*." + extension);
        fileDialog.setFilenameFilter(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith("." + extension);
            }
        });

        return fileDialog;
    }
}

测试

@Test
public void performsSaveAsWhenNetHasNoFile()
        throws AllKindsOfExceptions {
    NetName normalName = new NormalNetName("");
    when(mockNet.getName()).thenReturn(normalName);
    File file = new File("test.xml");

    //This will error out
    when(saveAction.getFileDialog("Save the world", "xml")).thenReturn(mockFileDialog);
    when(mockFileDialog.getFiles()).thenReturn(new File[]{file});

    saveAsAction.actionPerformed(null);
    verify(mockController).saveAsFile(file);
}

1 个答案:

答案 0 :(得分:1)

假设您使用相同的包并且(每个注释)可以从方法中删除final限定符,我会考虑添加一些protected setter方法,以便将mocks注入{{1} }。这有点争议,但它会起作用。

我有一个工作示例,但要点是生产代码中的以下内容:

AbstractSaveAction

然后测试看起来像:

public abstract class AbstractSaveAction extends GuiAction {
    // ...

    // for tests only. Consider naming as 'testFileDialog' if you prefer
    private FileDialog fileDialog = null;

    // for tests only
    protected void setFileDialog(FileDialog fileDialog) {
        this.fileDialog = fileDialog;
    }

    // for tests only
    protected void setController(Controller controller) {
        this.controller = controller;
    }

    protected FileDialog buildFileDialog(String title) {
        FileDialog result = null;

        if (this.fileDialog != null) {
            result = this.fileDialog;
        } else {
            result = new FileDialog(view, title, FileDialog.SAVE);
        }

        return result;
    }
    protected FileDialog getFileDialog(String title, final String extension) {
        // This is new. Get a FileDialog, and if in test-mode
        // so be it... It is a light-touch.
        FileDialog fileDialog = buildFileDialog(title);
        // ...
     }
}