`

Junit单测代码中java序列化失败的解决

    博客分类:
  • Java
 
阅读更多

本文主要介绍在Junit单元测试中序列化时出现的java.io.NotSerializableException如何解决。

关于序列化可以参见http://trinea.iteye.com/blog/1020511

 

以下是Junit单测中的一段代码,主要功能是序列化一个接口变量

interface GetDataInterface extends Serializable {

	public Object getData();
}

public void testSerializable() {

	GetDataInterface getData = new GetDataInterface() {

		private static final long serialVersionUID = 1L;

		@Override
		public Object getData() {
			return null;
		}
	};

	ObjectOutputStream out;
	try {
		out = new ObjectOutputStream(new FileOutputStream("getData.obj"));
		out.writeObject(getData);
		out.close();
		assertTrue(true);
	} catch (FileNotFoundException e) {
		e.printStackTrace();
		assertFalse(true);
	} catch (IOException e) {
		e.printStackTrace();
		assertFalse(true);
	}
}

Junit运行testSerializable函数会抛出IOException异常,如下

java.io.NotSerializableException: com.*.*.*.*.Test
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
	at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
	at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.writeObject(Unknown Source)
	at com.*.*.*.*.Test.testSerializable(AutoGetDataCacheTest.java:235)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at junit.framework.TestCase.runTest(TestCase.java:154)
	at junit.framework.TestCase.runBare(TestCase.java:127)
	at junit.framework.TestResult$1.protect(TestResult.java:106)
	at junit.framework.TestResult.runProtected(TestResult.java:124)
	at junit.framework.TestResult.run(TestResult.java:109)
	at junit.framework.TestCase.run(TestCase.java:118)
	at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

即找不到序列化的对象,这种情况一般出现在序列化对象的类没有实现Serializable接口,而这里明显已经实现了,将这段函数放到main函数中执行发现正常,接着比较就能发现main函数是静态的,我们将上面的testSerializable改成静态函数

public static void testSerializable() 

运行就会发现结果正常。  

 

我们再试试对于一个类来说会怎么样

    public class ClassImplSerialize implements Serializable {

        private static final long serialVersionUID = 88940079192401092L;
    }

    public void testSerializable() {

        ClassImplSerialize getData = new ClassImplSerialize();

        ObjectOutputStream out;
        try {
            out = new ObjectOutputStream(new FileOutputStream("getData.obj"));
            out.writeObject(getData);
            out.close();
            assertTrue(true);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            assertFalse(true);
        } catch (IOException e) {
            e.printStackTrace();
            assertFalse(true);
        }

    }

运行依旧会抛出上面类似的异常,这里我们将类ClassImplSerialize改为静态类,testSerializable依旧不变

public static class ClassImplSerialize implements Serializable

发现问题也可以解决。  

 

 

原因:

经评论中的鼎爷指点,总结原因如下

 

内部类有一个隐含的引用指向外部类,这样序列化他的时候,这个引用指向的对象必须也是可序列化的,否则就报错。(所以我们把Junit的测试用例类实现Serializable也可以解决上面的问题)

 

静态内部类不包含这个引用,所以只要自己可以序列化即可。

 

对于静态函数能够正常通过,是因为这个内部类被静态函数引用,所以自己也相当于是静态的效果,不存在对外部类的引用了。

更多感兴趣的可以看看评论1楼到4楼

 

 

 

分享到:
评论
5 楼 Trinea 2012-05-17  
oldrat 写道
Trinea 写道
oldrat 写道
JUnit4不允许test方法为static,JUnit 3是可以。
用JUnit 3写了一下,也包含了3个Case。UT通过。

soga,原来内部类有一个隐含的引用指向外部类,这样序列化他的时候,这个引用指向的对象必须也是可序列化的,否则就报错。

而静态内部类不包含这个引用,所以只要自己可以序列化即可。

那对于静态函数能够正常通过,是因为这个内部类被静态函数引用,所以自己也相当于是静态的效果,不存在对外部类的引用了?



> 那对于静态函数能够正常通过,是因为这个内部类被静态函数引用,所以自己也相当于是静态的效果,不存在对外部类的引用了?
是的。静态函数里的匿名内部类,只能成为静态类,因为静态函数没有关联this引用。非静态函数(成员函数)有关联this引用,所以可以编译成非静态的内部类。

Java应该是没有办法可以在成员函数里声明一个静态的内部类的。

有人知道 如何“可以在成员函数里声明一个静态的内部类”,如果可以,给一下代码。

函数里面声明静态内部类昨天我也试过了,不行
4 楼 oldrat 2012-05-17  
Trinea 写道
oldrat 写道
JUnit4不允许test方法为static,JUnit 3是可以。
用JUnit 3写了一下,也包含了3个Case。UT通过。

soga,原来内部类有一个隐含的引用指向外部类,这样序列化他的时候,这个引用指向的对象必须也是可序列化的,否则就报错。

而静态内部类不包含这个引用,所以只要自己可以序列化即可。

那对于静态函数能够正常通过,是因为这个内部类被静态函数引用,所以自己也相当于是静态的效果,不存在对外部类的引用了?



> 那对于静态函数能够正常通过,是因为这个内部类被静态函数引用,所以自己也相当于是静态的效果,不存在对外部类的引用了?
是的。静态函数里的匿名内部类,只能成为静态类,因为静态函数没有关联this引用。非静态函数(成员函数)有关联this引用,所以可以编译成非静态的内部类。

Java应该是没有办法可以在成员函数里声明一个静态的内部类的。

有人知道 如何“可以在成员函数里声明一个静态的内部类”,如果可以,给一下代码。
3 楼 Trinea 2012-05-17  
oldrat 写道
JUnit4不允许test方法为static,JUnit 3是可以。
用JUnit 3写了一下,也包含了3个Case。UT通过。

soga,原来内部类有一个隐含的引用指向外部类,这样序列化他的时候,这个引用指向的对象必须也是可序列化的,否则就报错。

而静态内部类不包含这个引用,所以只要自己可以序列化即可。

那对于静态函数能够正常通过,是因为这个内部类被静态函数引用,所以自己也相当于是静态的效果,不存在对外部类的引用了?
2 楼 oldrat 2012-05-17  
JUnit4不允许test方法为static,JUnit 3是可以。
用JUnit 3写了一下,也包含了3个Case。UT通过。

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import junit.framework.TestCase;

public class StaticClassSerializationTest extends TestCase {
    
    interface GetDataInterface extends Serializable {
        public Object getData();
    }

    static GetDataInterface getData = new GetDataInterface() {
        private static final long serialVersionUID = 1L;

        public Object getData() {
            return null;
        }
    };
    
    public static class ClassImplSerialize implements Serializable {
        private static final long serialVersionUID = 88940079192401092L;
    }
    
    public void testSerializable_Attribute_StaticAnonymousClass() throws Exception {
        ObjectOutputStream out = null;
        try {
            out = new ObjectOutputStream(new FileOutputStream("getData.obj"));
            out.writeObject(getData);
        } finally {
            if(null != out) {
                try {
                    out.close();
                } catch (Exception e) {}
            }
        }
    }

    public static void testSerializable_LocalVar_StaticAnonymousClass() throws Exception {
        GetDataInterface local = new GetDataInterface() {
            private static final long serialVersionUID = 1L;
            public Object getData() {
                return null;
            }
        };
        
        ObjectOutputStream out = null;
        try {
            out = new ObjectOutputStream(new FileOutputStream("getData.obj"));
            out.writeObject(local);
        } finally {
            if (null != out) {
                try {
                    out.close();
                } catch (Exception e) {
                }
            }
        }
    }
    
    public void testSerializable_StaticInnerClass() throws Exception {
        ClassImplSerialize getData = new ClassImplSerialize();

        ObjectOutputStream out = null;
        try {
            out = new ObjectOutputStream(new FileOutputStream("getData.obj"));
            out.writeObject(getData);
        } finally {
            if(null != out) {
                try {
                    out.close();
                } catch (Exception e) {}
            }
        }
    }
}
1 楼 oldrat 2012-05-17  
内部类是一个隐含的引用指向外部类。
UT失败是因为内部类不能序列化。
下面改了一下,把UT类实现Serializable,UT就都通过了。

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import org.junit.Test;

public class InnnerClassSerializationTest implements Serializable {
    private static final long serialVersionUID = 1L;

    interface GetDataInterface extends Serializable {
        public Object getData();
    }

    GetDataInterface attributeData = new GetDataInterface() {
           private static final long serialVersionUID = 1L;
           public Object getData() {
               return null;
           }
       };

    public class InnerClassSerialize implements Serializable {
        private static final long serialVersionUID = 88940079192401092L;
    }

    @Test
    public void testSerializable_Attribute_AnonymousClass() throws Exception {
        ObjectOutputStream out = null;
        try {
            out = new ObjectOutputStream(new FileOutputStream("getData.obj"));
            out.writeObject(attributeData);
        } finally {
            if (null != out) {
                try {
                    out.close();
                } catch (Exception e) {
                }
            }
        }
    }
    
    @Test
    public void testSerializable_LocalVar_AnonymousClass() throws Exception {
        GetDataInterface local = new GetDataInterface() {
            private static final long serialVersionUID = 1L;
            public Object getData() {
                return null;
            }
        };
        
        ObjectOutputStream out = null;
        try {
            out = new ObjectOutputStream(new FileOutputStream("getData.obj"));
            out.writeObject(local);
        } finally {
            if (null != out) {
                try {
                    out.close();
                } catch (Exception e) {
                }
            }
        }
    }

    @Test
    public void testSerializable_InnerClass() throws Exception {
        InnerClassSerialize getData = new InnerClassSerialize();

        ObjectOutputStream out = null;
        try {
            out = new ObjectOutputStream(new FileOutputStream("getData.obj"));
            out.writeObject(getData);
        } finally {
            if (null != out) {
                try {
                    out.close();
                } catch (Exception e) {
                }
            }
        }
    }
}


另外可以把内部声明成static的,这样就没有隐含的指向外部类的引用,UT也可以通过。
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import org.junit.Test;

public class StaticClassSerializationTest {
    
    interface GetDataInterface extends Serializable {
        public Object getData();
    }

    static GetDataInterface getData = new GetDataInterface() {
        private static final long serialVersionUID = 1L;

        public Object getData() {
            return null;
        }
    };
    
    public static class ClassImplSerialize implements Serializable {
        private static final long serialVersionUID = 88940079192401092L;
    }
    
    @Test
    public void testSerializable_Attribute_StaticAnonymousClass() throws Exception {
        ObjectOutputStream out = null;
        try {
            out = new ObjectOutputStream(new FileOutputStream("getData.obj"));
            out.writeObject(getData);
        } finally {
            if(null != out) {
                try {
                    out.close();
                } catch (Exception e) {}
            }
        }
    }
    
    @Test
    public void testSerializable_StaticInnerClass() throws Exception {
        ClassImplSerialize getData = new ClassImplSerialize();

        ObjectOutputStream out = null;
        try {
            out = new ObjectOutputStream(new FileOutputStream("getData.obj"));
            out.writeObject(getData);
        } finally {
            if(null != out) {
                try {
                    out.close();
                } catch (Exception e) {}
            }
        }
    }
}

相关推荐

    JUnit教程工程代码实例+PDF下载.zip

    JUnit是Java编程语言中最常用的单元测试框架之一,它允许开发者编写可重复执行的测试用例,以验证代码的正确性。JUnit提供了注解(Annotations)如@Test、@Before和@After等,使得编写测试变得简单且直观。下面是...

    json+junit的jar包

    例如,Jackson库提供了高效的JSON序列化和反序列化功能,允许我们将Java对象转换为JSON字符串,反之亦然。Gson则是Google提供的一个开源库,同样支持将Java对象转换成JSON格式,同时可以将JSON字符串映射回相应的...

    junit pdf

    随着软件工程领域对自动化测试重视程度的增加,JUnit 成为了 Java 开发者不可或缺的工具之一。 #### Test-Driven Development (TDD) 介绍 TDD 是一种软件开发方法论,其核心思想是在编写实际功能代码之前先编写...

    ANT执行junit

    JUnit,则是Java编程语言中最广泛使用的单元测试框架,它允许开发人员编写可重复运行的测试用例,以确保代码的质量和功能稳定性。 在Ant中执行JUnit测试,首先需要确保系统中已经安装了JUnit库,通常通过Maven或...

    JAVA聊天室完整代码

    4. **对象序列化**:如果聊天室需要传递复杂的数据结构(如用户对象),那么Java的对象序列化就派上了用场。通过实现Serializable接口,对象可以转换为字节流在网络中传输。 5. **设计模式**:为了实现聊天室的功能...

    JUnit的框架设计及其使用的设计模式

    JUnit是Java编程语言中最常用的单元测试框架之一,它在软件开发过程中起着至关重要的作用,确保代码的质量和可维护性。这个框架的设计基于一系列高效的设计模式,这些模式不仅提升了JUnit的灵活性,还使得开发者能够...

    使用用例场景设计测试用例 测试 软件工程 JUnit

    JUnit是Java编程语言中最常用的单元测试框架。它允许开发者编写可重复执行的测试代码,以验证程序的各个模块是否按照预期工作。JUnit提供了丰富的注解(如@Test)、断言方法(如assertEquals)以及测试套件管理工具...

    JAVA短信发送资料代码、教程

    Java标准库中的`org.json`包或Gson、Jackson等库可以帮助你处理JSON的序列化和反序列化。 5. **错误处理**:在发送短信的过程中,可能会遇到各种问题,如网络连接失败、超时、无效的短信验证码等。你需要编写适当的...

    junit eclipse testcast Testsuite

    JUnit支持注解(annotations)、测试套件(test suites)、参数化测试等多种特性,极大地简化了测试代码的编写。 二、Eclipse Testcast Testsuite介绍 Eclipse Testcast Testsuite是Eclipse IDE的一个插件,专为...

    Java聊天室客户端

    7. **数据序列化与反序列化**:为了在网络上传输对象,如用户信息,Java提供了序列化机制。序列化可以将对象转换为字节流,然后在网络上传输;反序列化则是接收字节流并恢复为原来的对象。 8. **错误处理**:为了...

    Java网络聊天应用完整源代码

    4. **数据序列化与反序列化**:如果消息包含自定义对象,可能需要使用Java的序列化机制将对象转换为字节流进行传输,然后再在另一端反序列化恢复对象。 5. **设计模式**:简单的聊天应用可能采用单例模式来管理...

    java 编的QQ程序

    在Java编程世界中,这样的项目可以帮助开发者深入理解多线程、网络通信、数据序列化以及对象交互等核心概念。 1. **多线程技术**: - 在`Server2.java`中,服务器端通常需要处理多个客户端的连接请求,因此会涉及...

    java的控制台聊天

    Java的`java.io.Serializable`接口标记对象可序列化,`ObjectOutputStream`和`ObjectInputStream`类则用于序列化和反序列化操作。 6. **异常处理(Exception Handling)**:在网络通信中,可能会出现各种异常,如...

    Java版 Steam API源码

    项目中可能会使用如Jackson或Gson这样的库来进行JSON序列化和反序列化。 4. **OAuth认证**:为了访问某些特定的Steam API功能,如用户的私有信息,开发者需要使用OAuth进行身份验证。Java Steam API中会包含处理...

    JAVA用户信息查找

    而如果涉及序列化,ObjectInputStream和ObjectOutputStream可以用来持久化对象。 6. **数据库操作**:在实际项目中,用户信息通常存储在数据库中。Java提供了JDBC(Java Database Connectivity)接口来与各种类型的...

    java源代码:日程管理小程序

    在Java中,可以使用JDBC(Java Database Connectivity)来连接到数据库,或者使用序列化技术将对象持久化到文件中。 3. **事件处理**:Java事件处理机制允许用户与UI进行交互。例如,当用户点击“添加日程”按钮时...

    NetworkProtocol1_java_

    4. **数据序列化和反序列化**:在网络传输中,对象通常需要转换为字节流,以便在网络中传输。Java的Serializable接口和ObjectInputStream/ObjectOutputStream类用于实现这一过程。 5. **异常处理**:网络操作可能会...

    Java课表管理系统源码.zip

    - **序列化与反序列化**:为了持久化存储课程数据,Java的序列化API可用于将对象转化为二进制流并写入磁盘。 - **XML或JSON解析**:可能使用XML或JSON格式存储数据,需要对应的解析库,如JAXB或Jackson,进行数据...

    TDD-learn-demo1

    通过这样的实践,开发者不仅可以熟悉TDD的工作流程,还能深入理解protobuf的工作原理,例如如何定义protobuf消息类型,如何使用protobuf编译器生成Java代码,以及如何在实际应用中使用序列化和反序列化的方法。...

    Java模拟银行小项目.zip

    例如,可以使用`FileInputStream`和`FileOutputStream`读写文件,或者使用`ObjectInputStream`和`ObjectOutputStream`进行对象序列化和反序列化。 7. **控制结构**:项目中会用到各种控制结构,如条件语句(`if-...

Global site tag (gtag.js) - Google Analytics