views:

96

answers:

4

I'm trying to build an automatic testing framework (based on jUnit, but that's no important) for my student's homework. They will have to create constructors of some classes, and add them methods. Then, with the testing functions I provide, they will check if they went allright.

What I want to do is, by reflection, create a new instance of some class I want to test. The problem is that, sometimes, there is no default constructor. I don't care about that, I want to create an instance an initialize the instance variables myself. Is there any way of doing this? I'm sorry if this has been asked before, but just I couldn't find any answer.

Thanks in advance.

+2  A: 

Call Class.getConstructor() and then Constructor.newInstance() passing in the appropriate arguments. Sample code:

import java.lang.reflect.*;

public class Test {

    public Test(int x) {
        System.out.println("Constuctor called! x = " + x);
    }

    // Don't just declare "throws Exception" in real code!
    public static void main(String[] args) throws Exception {
        Class<Test> clazz = Test.class;
        Constructor<Test> ctor = clazz.getConstructor(int.class);
        Test instance = ctor.newInstance(5);           
    }
}
Jon Skeet
It will involve some messy reflection to get a constructor, and walk it, giving an appropriate value for each argument...
bwawok
Thanks. The problem is that i don't know if they already added the constructor or not. Of course, i could check if they did by catching the apropriate exception. But i wouldn't know if they created the constructor with the correct arguments. Even worse, i don't know if the constructor work OK. I'd like to build the instance without depending on their implementation.
GermanK
@GermanK: Use Class.getConstructors() then instead and see what's available. You *have* to depend on an implementation in order to instantiate a class. If you create an instance without calling one of their constructors with appropriate arguments, you're not playing fair to their classes, which would *expect* to be instantiated properly. I suggest you *mandate* a particular signature.
Jon Skeet
@GermanK Then have a vararg at the end of your test method where the user inputs the necessary arguments
TheLQ
@Jon Skeet: I do mandate a particular signature. What if they don't respect it? One factible option i have is to test their Constructor and tell them that until they don't build up that part correctly, they won't be able to test any other method. If there is no better alternative, i think that's what i'll stick with.
GermanK
@GermanK: If they don't implement that constructor, the test should fail, surely. If you've specified particular constructor then I suggest you just call `getConstructor()` with the appropriate types: if an exception is thrown, so be it - the test will fail, which is the correct behaviour. You *could* explicitly look for the constructor first (using `getConstructors()`) and fail with a more explicit error message, of course.
Jon Skeet
@GermanK, u r the prof. If the student did not do the assignment properly, the student has failed. Give them feedback about why they failed. Next time, they will be more careful.
emory
Thanks everyone. I've been wondering around the javassist library which can handle modifications on runtime of Java classes. The problem is that i'd have to mess with the class loaders on JUnit to add the modifications I'd need before the class is efectively loaded, and it'd be too much mess. So i'm finally staying with this much simpler solution: ask them to build the constructors.
GermanK
A: 

You can use Class.getConstructor or Class.getConstructors and then use the method Constructor.newInstance to initialize the object that you want to use.

Dani Cricco
With Class.getConstructor or Class.getDeclaredConstructor with no parameters you get a java.lang.NoSuchMethodException if there is no default constructor declared
GermanK
A: 

If you haven't used mocking frameworks (like ezmock) I highly recommend you give one a try.

I may be wrong and that may not help you at all, but from what I could gather from your post it seems possible that mocking may be exactly what you are looking for (Even though I recognize that it has nothing to do with what you asked for.

Edit: In response to comment.

No, Modern mocking frameworks allow you to create a "Fake" instance of any class from "nothing" and pass it around as though it was an instance of the class. It doesn't need an interface, it can be any class. Also methods can be scripted to return a sequence of values from a simple always return "7" to "When called with an arg=7 return 5 the first call, 6 the second and 7 the third".

It's usually used in conjunction with testing frameworks to give a reference class to pass to the class you are testing.

This may not be exactly what you are looking for, but you mentioned unit testing and manually initializing variables so it seemed like this is something that may eventually come in handy.

Bill K
i think this requires some interface that the mocking framework will implement, right? Because i don't have interfaces... They are very simple classes the ones that the students will implement.
GermanK
OK, thanks, it might be useful some other time.
GermanK
A: 

You could distribute the following source code with your assignment. Tell the students to include it in their source code. Their code won't compile unless they code an Assignment class with the proper signature. The compiler does the signaure checking for you.

Then your testing program does not need to use reflection. Just instantiate an AssignmentFactory and call the make method with the proper arguments.

If you use this idea, your new challenge will be some students modifying AssignmentFactory to fit their Assignment class (breaking your testing program).

package assignment ;

public class AssignmentFactory
{
     public AssignmentFactory ( )
     {
           super ( ) ;
     }

     public AssignmentFactory make ( .... parameters )
     {
           return new Assignment ( .... arguments ) ;
     }
}
emory
This just will take part of the testing (signature correctness) to compile time... What would happen if they don't initialize correctly the instance variables? I'd still need to test them anyway. On the other hand, i don't want to add anything that would distract them from their main goal in their assignment.
GermanK
Yes, you would still need to evaluate their assignment. The purpose of the AssignmentFactory is to try to force them to submit their assignment in a format that is suitable for programmatic evaluation.
emory