Search code examples
unit-testingjunitjavax.comm

Advice on unit testing, class to test has dependency on Java serial port


I am working on a large legacy java application. It already has an extensive existing framework in place for handling device drivers. I need to create a new device driver for a device that connects to a serial port via JavaComm.

The existing drivers simply create the new serial port inside their configure() methods, then create new input and output streams from the serial port object, then use those input and output streams for the device comms, but with no unit tests.

I want my new class to be unit testable however, but not sure how I can do that if it's going to fit in with this existing framework that will expect the serial port, input and output streams to be set up in the configure() method.

Any ideas?


    public void configure()
    {
        super.configure();

        if (isEmulated()) {
            return;
        }
        if (isFaulty()) {           
            if (isOutOfService()) {
                ZBopNotificationManager.getInstance().add(
                        new SystemNotice(SeverityCode.LEVEL3, getName(), getErrorMessage()));
            }
            return;         
         }

        // ZP:
        String portName = getSerialPort();
        // String portName = "COM1";
        try {
            CommPortIdentifier id = CommPortIdentifier.getPortIdentifier(portName);
            Trace.log(this, Trace.D, "Port name = " + id.getName());
            port = (SerialPort) id.open(getName(), 1000);
        } catch (NoSuchPortException nspe) {
            report(SeverityCode.LEVEL3, getName(), "Bar Code Scanner is not connected to " + portName + " port, or the port does not exist.");
            return;
        } catch (PortInUseException piue) {
            report(SeverityCode.LEVEL3, getName(), portName + " port is already in-use by some other device. Reason: " + piue.getMessage());
            return;
        }

        try {
            port.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
        } catch (UnsupportedCommOperationException e) {
            // this should not happen
            port.close();
            report(SeverityCode.LEVEL2, getName(), portName + " port configuration failed: " + e);
            return;
        }

        try {
            in = port.getInputStream();
            out = port.getOutputStream();
        } catch (IOException ioe) {
            port.close();
            report(SeverityCode.LEVEL3, getName(), portName + " port configuration failed: " + ioe.getMessage());
            return;
        }
meout(30);

        // ... other init code omitted
    }



Solution

  • By the looks of things, the javax.comm API doesn't make life easy for unit tests - it's big on classes, and light on interfaces.

    My suggest would be to create interfaces and adaptor classes for each javax.comm class that you need to use in your driver. Your driver code would then talk to those interfaces, rather than directly to javax.comm. You probably only need a subset of the API anyway, and defining these interfaces should help you clarify your design.

    This will allow you to use mock implementations of those interfaces in your unit tests (e.g. JMock, Mockito, etc). Your unit test can inject these mocks into the driver object.

    When used for real, the driver's configure() method can instantiate the adaptor classes rather than the mocks.