[SalesForce] Method Is Not Visible: APEX Trailhead Unit Testing Challenge

PROBLEM:
I am receiving a "Method is not visible: Boolean VerifyDate.DateWithin30Days(Date, Date)" on my 3rd, 4th, and 5th. I am also receiving a "Method is not visible: Date VerifyDate.SetEndOfMonthDate(Date)" on my 6th method. Does anyone have any ideas? Your help would be greatly appreciated. Thank you!

CHALLENGE:
Create a unit test for a simple Apex class.

Install a simple Apex class, write unit tests that achieve 100% code coverage for the class, and run your Apex tests.

The Apex class to test is called 'VerifyDate', and the code is available here. Copy and paste this class into your Developer Edition via the Developer Console.
'VerifyDate' is a class which tests if a date is within a proper range, and if not will return a date that occurs at the end of the month within the range.
The unit tests must be in a separate test class called 'TestVerifyDate'.
The unit tests must cover scenarios for all lines of code included in the Apex class, resulting in 100% code coverage.

Run your test class at least once (via 'Run All' tests the Developer Console) before attempting to verify this challenge.

VERIFY DATE:

public class VerifyDate {

    //method to handle potential checks against two dates
    public static Date CheckDates(Date date1, Date date2) {
        //if date2 is within the next 30 days of date1, use date2.  Otherwise use the end of the month
        if(DateWithin30Days(date1,date2)) {
            return date2;
        } else {
            return SetEndOfMonthDate(date1);
        }
    }

    //method to check if date2 is within the next 30 days of date1
    private static Boolean DateWithin30Days(Date date1, Date date2) {
        //check for date2 being in the past
            if( date2 < date1) { return false; }

            //check that date2 is within (>=) 30 days of date1
            Date date30Days = date1.addDays(30); //create a date 30 days away from date1
        if( date2 >= date30Days ) { return false; }
        else { return true; }
    }

    //method to return the end of the month of a given date
    private static Date SetEndOfMonthDate(Date date1) {
        Integer totalDays = Date.daysInMonth(date1.year(), date1.month());
        Date lastDay = Date.newInstance(date1.year(), date1.month(), totalDays);
        return lastDay;
    }

}

MY CODE FOR TESTING:

@isTest
private class TestVerifyDate
    {
      @isTest static void testCheckDatesOne ()
      {
        Date test = VerifyDate.CheckDates (Date.newInstance(2018, 7, 19), Date.newInstance(2018, 7, 20));
        System.assertEquals(Date.newInstance(2018, 7, 20), test);
      }

    @isTest static void testCheckDatesTwo ()
    {
        Date test = VerifyDate.CheckDates (Date.newInstance(2018, 7, 19), Date.newInstance(2018, 8, 20));
        System.assertEquals(Date.newInstance(2018, 8, 20), test);

    }

    @isTest static void testDateWithin30DaysOne ()
    {
        boolean test = VerifyDate.DateWithin30Days (Date.newInstance(2018, 7, 19), Date.newInstance(2018, 7, 18));
        System.assertEquals(false, test);
    }

    @isTest static void testDateWithin30DaysTwo ()
    {
        boolean test = VerifyDate.DateWithin30Days (Date.newInstance(2018, 7, 19), Date.newInstance(2019, 1, 1));
        System.assertEquals(false, test);
    }

    @isTest static void testDateWithin30DaysThree ()
    {
        boolean test = VerifyDate.DateWithin30Days (Date.newInstance(2018, 7, 19), Date.newInstance(2018, 7, 19));
        System.assertEquals(true, test);
    }

    @isTest static void testSetEndOfMonthDate ()
    {
        Date test = VerifyDate.SetEndOfMonthDate (Date.newInstance(2018, 7, 19));
        System.assertEquals(Date.newInstance(2018, 7, 31), test);
    }

}

Best Answer

The reason that your test method can't see your operational method is because your operational method was declared as private.

private

This is the default, and means that the method or variable is accessible only within the Apex class in which it is defined. If you do not specify an access modifier, the method or variable is private.

Your test method is outside the class your (private) operational method is in, so it doesn't have access to it. There is an annotation (sometimes called a "decorator") that you can add to a private method to make it visible to the test context. It's @TestVisible

Use the TestVisible annotation to allow test methods to access private or protected members of another class outside the test class. These members include methods, member variables, and inner classes. This annotation enables a more permissive access level for running tests only. This annotation doesn’t change the visibility of members if accessed by non-test classes.

With this annotation, you don’t have to change the access modifiers of your methods and member variables to public if you want to access them in a test method. For example, if a private member variable isn’t supposed to be exposed to external classes but it should be accessible by a test method, you can add the TestVisible annotation to the variable definition.