2
\$\begingroup\$

I am attempting to build an Android APP with the custom serializable class User. The public method Save is to save class instance information and the public method Load is to load saved information from the specified file.

The experimental implementation

  • Project name: UserClassSerialization

  • User.java implementation:

    package com.example.userclassserialization;
    
    import android.content.Context;
    import android.util.Log;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    
    
    public class User  implements java.io.Serializable{
        private String fullName;
        private String personalID;
        private String dateOfBirth;
        private String cellPhoneNumber;
        private String emailInfo;
        private String password;
    
    
        public User(String fullNameInput,
                    String personalIDInput,
                    String dateOfBirthInput,
                    String cellPhoneNumberInput,
                    String emailInfoInput,
                    String passwordInput) throws NoSuchAlgorithmException             //  User object constructor
        {
            this.fullName = fullNameInput;
            this.personalID = personalIDInput;
            this.dateOfBirth = dateOfBirthInput;
            this.cellPhoneNumber = cellPhoneNumberInput;
            this.emailInfo = emailInfoInput;
            this.password = HashingMethod(passwordInput);
        }
    
        public String GetFullName()
        {
            return this.fullName;
        }
        public String GetPersonalID()
        {
            return this.personalID;
        }
    
        public String GetDateOfBirth()
        {
            return this.dateOfBirth;
        }
    
        public String GetCellPhoneNumber()
        {
            return this.cellPhoneNumber;
        }
    
        public String GetEmailInfo()
        {
            return this.emailInfo;
        }
    
        public String GetHash() throws NoSuchAlgorithmException
        {
            return HashingMethod(this.fullName + this.personalID);
        }
    
        public String GetHashedPassword() throws NoSuchAlgorithmException
        {
            return this.password;
        }
    
        public boolean CheckPassword(String password)
        {
            boolean result = false;
            try {
                result = this.password.equals(HashingMethod(password));
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            return result;
        }
    
        //  Reference: https://stackoverflow.com/a/4118917/6667035
        //  fileName cannot contain any path separator
        public boolean Save(Context context, String fileName)
        {
            try {
                FileOutputStream fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
                ObjectOutputStream os = new ObjectOutputStream(fos);
                os.writeObject(this);
                os.close();
                fos.close();
                return true;
            } catch (IOException i) {
                i.printStackTrace();
                return false;
            }
        }
    
        public void Load(Context context, String fileName){
            try {
                FileInputStream fis = context.openFileInput(fileName);
                ObjectInputStream is = new ObjectInputStream(fis);
                User simpleClass = (User) is.readObject();
                is.close();
                fis.close();
                this.fullName = simpleClass.fullName;
                this.personalID = simpleClass.personalID;
                this.dateOfBirth = simpleClass.dateOfBirth;
                this.cellPhoneNumber = simpleClass.cellPhoneNumber;
                this.emailInfo = simpleClass.emailInfo;
                this.password = simpleClass.password;
            } catch (Exception e){
                e.printStackTrace();
            }
        }
        //**********************************************************************************************
    
        //  Reference: https://stackoverflow.com/a/2624385/6667035
        private String HashingMethod(String InputString) throws NoSuchAlgorithmException
        {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
            String stringToHash = InputString;
            messageDigest.update(stringToHash.getBytes());
            String stringHash = new String(messageDigest.digest());
            return stringHash;
        }
    }
    

Full Testing Code

  • Unit Tests

    package com.example.userclassserialization;
    
    import junit.framework.TestCase;
    
    public class UserTest extends TestCase {
    
        public void testGetFullName() {
            User User1 = null;
            try {
                User1 = new User(
                        "Mike",
                        "M12345678",
                        "1990/10/13",
                        "(555) 555-1234",
                        "[email protected]",
                        "password");
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            assertEquals("Mike", User1.GetFullName());
        }
    
        public void testGetPersonalID() {
            User User1 = null;
            try {
                User1 = new User(
                        "Mike",
                        "M12345678",
                        "1990/10/13",
                        "(555) 555-1234",
                        "[email protected]",
                        "password");
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            assertEquals("M12345678", User1.GetPersonalID());
        }
    
        public void testGetDateOfBirth() {
            User User1 = null;
            try {
                User1 = new User(
                        "Mike",
                        "M12345678",
                        "1990/10/13",
                        "(555) 555-1234",
                        "[email protected]",
                        "password");
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            assertEquals("1990/10/13", User1.GetDateOfBirth());
        }
    
        public void testGetCellPhoneNumber() {
            User User1 = null;
            try {
                User1 = new User(
                        "Mike",
                        "M12345678",
                        "1990/10/13",
                        "(555) 555-1234",
                        "[email protected]",
                        "password");
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            assertEquals("(555) 555-1234", User1.GetCellPhoneNumber());
        }
    
        public void testGetEmailInfo() {
            User User1 = null;
            try {
                User1 = new User(
                        "Mike",
                        "M12345678",
                        "1990/10/13",
                        "(555) 555-1234",
                        "[email protected]",
                        "password");
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            assertEquals("[email protected]", User1.GetEmailInfo());
        }
    
        public void testCheckPassword() {
            User User1 = null;
            try {
                User1 = new User(
                        "Mike",
                        "M12345678",
                        "1990/10/13",
                        "(555) 555-1234",
                        "[email protected]",
                        "password");
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            assertEquals(true, User1.CheckPassword("password"));
            assertEquals(false, User1.CheckPassword("password1"));
        }
    }
    
  • MainActivity.java implementation:

    package com.example.userclassserialization;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.content.Context;
    import android.os.Bundle;
    import android.widget.Toast;
    
    public class MainActivity extends AppCompatActivity {
    
        private User CurrentUser = null;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            try {
                CurrentUser = new User(
                        "Mike",
                        "M12345678",
                        "1990/10/13",
                        "(555) 555-1234",
                        "[email protected]",
                        "password");
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            SaveCurrentUser();
            LoadCurrentUser();
            ShowToast(CurrentUser.GetFullName(), Toast.LENGTH_SHORT);
        }
    
        private boolean SaveCurrentUser()
        {
            return CurrentUser.Save(this, "User.ser");
        }
    
        private void LoadCurrentUser()
        {
            CurrentUser.Load(this, "User.ser");
        }
    
        private void ShowToast(String Text, int Duration)
        {
            Context context = getApplicationContext();
            CharSequence text = Text;
            int duration = Duration;
    
            Toast toast = Toast.makeText(context, text, duration);
            toast.show();
        }
    }
    

If there is any possible improvement, please let me know.

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Just a couple of points with your unit tests.

Test cases

It's unusual to see extends TestCase. This appears to have been the way it worked in JUnit 3, no I'd expect each of your test cases to be annotated with @Test. There's more discussion here.

Exceptions

Each of your tests has a block in it to catch exceptions from the constructor and then swallows it.

catch (Exception e)
{
    e.printStackTrace();
}

You don't really want to do this in your test cases. You want the exceptions to escape, so that they are caught by the testing framework. This will automatically mark the test as failed.

public void testGetFullName() throws Exception {
    User user = new User(
                "Mike",
                "M12345678",
                "1990/10/13",
                "(555) 555-1234",
                "[email protected]",
                "password");
    assertEquals("Mike", user.GetFullName());
}

What are you really testing...

You tests really just test that your constructor assigned the field values and that your get methods work. This is pretty basic functionality, the more complex elements of your class, are the Load/Save aspects, which you don't actually seem to test.

Other observations

  • Load is an instance method that updates the instance. So, in order to load an instance, you first have to create an instance of user (which doesn't have a default constructor, so you need to supply arguments for all of the members), then call Load and throw away all of the pre-populated information. This feels wrong. A static load that returns a new instance of a User might be closer, or a better solution would probably be to move the save/load logic out of the user class altogether into a class that knows about loading/saving.

  • SaveCurrentUser returns a boolean, but you don't seem to actually use it anywhere.

  • GetHashedPassword says it throws NoSuchAlgorithmException, but it doesn't

  • CheckPassword catches Exception, you rarely want to do this. Generally you should catch the most specific exception you can.

\$\endgroup\$
1
  • \$\begingroup\$ Agree with everything, moreover OP is using same initial data inside the app and tests so in case of error it would have been detected in the app. \$\endgroup\$ Commented May 16, 2021 at 9:07

Not the answer you're looking for? Browse other questions tagged or ask your own question.