简体   繁体   中英

Why do i need a constructor in an abstract class?

I'm currently working my way through a java tutorial, where i am being introduced to abstract classes and testing with J-Unit.

I have 2 files, AthleteTest & BikerTest, with BikerTest extending AthleteTest.AthleteTest contains the common methods and variables of my different tests, while BikerTest contains the specifics.

ATHLETETEST

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;


public abstract class AthleteTest 
{
    private Athlete a1;
    private Athlete a2;
    protected String _name = "Test Athlete";
    protected int _age = 32;
    protected int _racerId = 987654;

    public abstract Athlete getAthlete();
    public abstract Athlete getExplicitAthlete();

    public AthleteTest()
    {
        a1 = getAthlete();
        a2 = getExplicitAthlete();
    }

    @Before
    public void setUp() throws Exception {
    }

    @After
    public void tearDown() throws Exception {
    }

    @Test
    public void testConstructors()
    {
        assertNotNull("Default Runner could not be created", a1);
        assertNotNull("Explicit Runner could not be created", a2);
        assertEquals("Name not set correctly on a2"
                        , _name
                        , a2.getName());
        assertEquals("Age not set correctly on a2"
                        , _age
                        , a2.getAge());
        assertEquals("RacerID not set correctly on a2"
                        , _racerId
                        , a2.getRacerId());
    }

    @Test
    public void testGetSetName()
    {
        a1.setName(_name);
        assertEquals("The name could not be set as expected"
                        , _name
                        , a1.getName());
    }

    @Test
    public void testGetSetAge()
    {
        a1.setAge(_age);
        assertEquals("The age could not be set as expected"
                        , _age
                        , a1.getAge());
    }

    @Test
    public void testGetSetRacerId()
    {
        a1.setRacerId(_racerId);
        assertEquals("The racerId could not be set as expected"
                        , _racerId
                        , a1.getRacerId());
    }

    public abstract void testPerformRaceActivity();

    @Test
    public void testToString()
    {
        a1.setName(_name);
        a1.setAge(_age);
        a1.setRacerId(_racerId);
        String rts = a1.toString();
        assertTrue("To String does not contain name"
                    , rts.contains(_name));
        assertTrue("To String does not contain age"
                    , rts.contains(String.format("%d", _age)));
        assertTrue("To String does not contain racer id"
                    , rts.contains(String.format("%d", _racerId)));
        String rc = a1.getClass().toString();
        assertTrue("To String does not contain class"
                    , rts.contains(rc));

    }

}

BIKERTEST

import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;


public class BikerTest extends AthleteTest
{
    private Biker r;
    private String raceActivity = "Biking";
    private boolean usesClips = false;

    @Override
    public Athlete getAthlete() {
        return new Biker();
    }

    @Override
    public Athlete getExplicitAthlete() {
        return new Biker(_name,_age,_racerId,usesClips);
    }


    @Before
    public void setUp()
    {
        r = new Biker();
    }

    @After
    public void tearDown()
    {
        r = null;
    }

    @Test
    public void testConstructors()
    {
        super.testConstructors();
        Biker r2 = new Biker(_name, _age, _racerId, usesClips);
        assertNotNull("Explicit Biker could not be created", r2);
        assertEquals("Name not set correctly on R2"
                        , _name
                        , r2.getName());
        assertEquals("Age not set correctly on R2"
                        , _age
                        , r2.getAge());
        assertEquals("RacerID not set correctly on R2"
                        , _racerId
                        , r2.getRacerId());
        assertEquals("UsesClips not set correctly on R2"
                , usesClips
                , r2.getUsingClips());
    }


    @Test
    public void testGetSetUsingClips()
    {
        r.setUsingClips(usesClips);
        assertEquals("The clips could not be set as expected"
                        , usesClips
                        , r.getUsingClips());
    }

    @Test
    public void testPerformRaceActivity()
    {
        String pra = r.performRaceActivity();
        assertTrue("Perform race activity did not contain activity"
                        , pra.contains(raceActivity));
    }

    @Test
    public void testToString()
    {
        super.testToString();
        r.setName(_name);
        r.setAge(_age);
        r.setRacerId(_racerId);
        r.setUsingClips(usesClips);
        String rts = r.toString();
        assertTrue("To String does not contain using clips"
                , rts.contains(String.format("%b", usesClips)));
        assertTrue("To string does not contain performRaceActivity"
                    , rts.contains(raceActivity));

    }



}

Now, while my files and code is working(it's taken from an example provided), i can't figure out why it's working as the tutorial does not go into details of how the test is executed.

QN1 Why do i need a constructor in the abstract class AthleteTest?My understanding is that because it is abstract, it will not be instantiated, therefore there is no need for a constructor as constructors only come into play when the class is instantiated.

QN2 How is the testing done; what is the testing order like ? For example,when i run BikerTest, while i override the GetAthlete and GetExplicitAthlete classes, i do not actually run the methods in the code.Yet why is it when i run the code, the methods are run. Does JUnit simply run all methods by default?

QN3 How is the superclass AthleteTest instantiated and work when i run BikerTest? For example, in BikerTest, i made calls to super - which is AthleteTest.Is AthleteTest instantiated/ created at the point when i make a call to super - and the resulting object is stored in a1 & a2, or is it created somewhen and somewhere else?

Thanks in advance for any clarification and explanations provided!

Why do i need a constructor in the abstract class AthleteTest?My understanding is that because it is abstract, it will not be instantiated

That's right. An abstract class cannot be instantiated. Although, that does not mean that abstract classes cannot have constructors. If you don't add a constructor to a class, the compiler will add a default no-arg constructor for you. This is true for abstract classes as well. Also, every constructor in Java has an implicit super() call as it's first line which calls the constructor of the parent class (including the default constructor added by the compiler). In your example, BikerTest does not have an explicit constructor. The compiler will therefore add the following constructor to BikerTest class :

public BikerTest() {
    super();
}

As soon as you run the BikerTest JUnit class, JUnit creates an instance of the BikerTest class and the super() call in the BikerTest constructor will cause the constructor of the AthleteTest class to be called.

For example,when i run BikerTest, while i override the GetAthlete and GetExplicitAthlete classes, i do not actually run the methods in the code.Yet why is it when i run the code, the methods are run

As explained earlier, the super() call in BikerTest results in the no-arg constructor of AtheleteTest class being called. The AtheleteTest class calls the getAthlete() and the getExplicitAthlete() methods. While these methods are abstract, they have been overriden in the BikerTest class. The methods from the BikerTest class will be called because the object created is of the class BikerTest

How is the superclass AthleteTest instantiated and work when i run BikerTest? For example, in BikerTest, i made calls to super - which is AthleteTest.Is AthleteTest instantiated/ created at the point when i make a call to super - and the resulting object is stored in a1 & a2, or is it created somewhen and somewhere else?

No. Calling methods using super or accessing fields using super does not result in the super class being instantiated (regardless of whether it is abstract or not). The r variable is assigned an object in the setUp method which is the first method that JUnit will call before running any tests. The a1 and a2 variables are assigned an object when BikerTest was instantiated and the AtheleteTest no-arg constructor was called (as explained earlier)

  1. Why do i need a constructor in the abstract class AthleteTest?My understanding is that because it is abstract, it will not be instantiated, therefore there is no need for a constructor as constructors only come into play when the class is instantiated.

Abstract classes cannot be instantiated directly - they must be subclassed by a non-abstract class, and that subclass can be instantiated. But when you instantiate a subclass, all the fields of the superclass are also part of the object that you created. And also, the constructor of the abstract superclass is called.

  1. How is the testing done; what is the testing order like ? For example,when i run BikerTest, while i override the GetAthlete and GetExplicitAthlete classes, i do not actually run the methods in the code.Yet why is it when i run the code, the methods are run. Does JUnit simply run all methods by default?

When you run a class as a test with JUnit 4, all the methods annotated with @Test are run as test methods. The methods annotated with @Before are run before each test is run, and the ones with @After, after each test.

There are more annotations that you can use, such as @BeforeClass and @AfterClass.

  1. How is the superclass AthleteTest instantiated and work when i run BikerTest? For example, in BikerTest, i made calls to super - which is AthleteTest.Is AthleteTest instantiated/ created at the point when i make a call to super - and the resulting object is stored in a1 & a2, or is it created somewhen and somewhere else?

No, the superclass is instantiated at the time that you instantiated the subclass. Actually, you created an object, and that object contains all the fields from the subclass that you instantiated and all its superclasses . So when JUnit created an instance of BikerTest for you, all fields from AthleteTest (being the superclass of BikerTest where also created as part of the object. And the constructor of AthleteTest was also called.

A constructor in an abstract class can be used to initalize your class for example if you use a final attribute. And the constructor from your subclass can call one constructor of the abstract class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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