1

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);
    }

}
1
  • You should read about the TestVisible Annotation but as I am not familiar with that Trailhead there may be a better way to go. Use that annotation as little as possible in real as it couples tests to implementation detail which is usually a bad thing.
    – Keith C
    Commented Jul 19, 2018 at 21:48

3 Answers 3

6

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.

1

I would like to concatenate answer above and a comment.

  1. To test private entities (variables, methods etc) you can use @TestVisible annotation. It will make those privates "visible" for tests.

  2. Don't do it. Especially in this case. Private entities are meant to be private and tests actually should test if this part of the code is available only from the place that make them available. So in your case from CheckDates method.

And answer to your question/issue.

To achieve full coverage you need to test 3 cases;

  1. CheckDates with date2 earlier than date1
  2. CheckDates with date2 later than date1 and later than 30 days
  3. CheckDates with date2 later than date1 but within 30 days.

That way you' will achieve full coverage.

Additionally good practice (in real world) is to test border cases like: Provided date would not be a date but another type. Test method giving null values for the dates etc.

Also another "good practice" is having limits and knowing when to stop testing. IMO developer should not write unit tests for exactly everything that can happen in the world. This example is pretty simple so there isn't much stuff that you can try to break but with slightly more sophisticated things there is possibility to write unit tests forever.

-1

Try the below code and press "Run All" under Tests tab

@isTest
public class TestVerifyDate {

    static testmethod void WithinMonthCheckDates(){
        Date date1 = date.today();
        Date date2 = date.today().addDays(15);
        Date date3 = date.today().addDays(45);
        Date date4 = date.today().addDays(-10);

        Date newDate = VerifyDate.CheckDates(date1,date2);
        System.assertEquals(date2, newDate);

        Date newDate2 = VerifyDate.CheckDates(date1,date3);
        System.assertEquals(date2, newDate);

        Date newDate3 = VerifyDate.CheckDates(date1,date4);
        System.assertEquals(date2, newDate);

       }
}
1
  • Welcome to SFSE! Please read How to Answer. Right now, this answer is what we call a code dump. It's a block of code with no explanation as to how it works or how it solves the problem. Code dumps tend to be poor answers because it doesn't help people understand what the issue was, or how to avoid similar issues in the future. They also tend to generate a lot of back-and-forth in the comments like "that didn't work" and "try this instead" which makes it hard for other people with similar issues to follow the chain from problem to solution.
    – Derek F
    Commented Aug 13, 2019 at 11:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .