Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit Testing a Class With A Private Constructor

I am trying to test a class that only has a private constructor. This is for a course registration system. The courses do not get create via our application, therefore we intentionally have no public constructor. Instead we use EF to get the courses that are already in the database, and register students to them.

I am trying to test the register method of the Course class, however I have no way of creating an instance. I could use course = (Course)Activator.CreateInstance(typeof(Course), true);, but then I don't have a way to setup the necessary properties since those are private.

What is the recommended approach for unit testing without a constructor?

This is a slimmed down version of the code.

public class Course
{
    private Course()
    {
    }

    public int Id { get; private set; }
    public string Name { get; private set; }
    public bool Open { get; private set; }
    public virtual ICollection<Student> Students { get; private set; }

    public void Register(string studentName)
    {
        if (Open)
        {
            var student = new Student(studentName);
            Students.Add(student);
        }
    }
}

// Usage //

using (var db = new SchoolContext())
        {
            var course = db.Courses.Include(x => x.Students).Where(x => x.Name == courseName).First();

            course.Register(studentName);
            db.SaveChanges();
        }

// Unit Test //

[Fact]
public void CanRegisterStudentForOpenClass(){
    // HERE I HAVE NO WAY TO CHANGE THE OPEN VARIABLE
    var course = (Course)Activator.CreateInstance(typeof(Course), true);
    course.Register("Bob");
}



    
like image 662
Ashley Avatar asked Dec 03 '22 17:12

Ashley


1 Answers

Yes you can using reflexion. your code is neraly there;

you can get properties and fields of the types with typeof(Course).GetProperty("PropertyName") then you can use SetValue to set the desired value, and pass as parameter first the instance to modify then the value. in your case true;

note: in your example you will need to add the Collection of students too, if your Open is true.

Here there is a working example:

[Fact]
public void CanRegisterStudentForOpenClass()
{
    var course = (Course)Activator.CreateInstance(typeof(Course), true);

    typeof(Course).GetProperty("Open").SetValue(course, true, null);
    ICollection<Student> students = new List<Student>();
    typeof(Course).GetProperty("Students").SetValue(course, students, null);

    course.Register("Bob");

    Assert.Single(course.Students);
}
like image 78
TiGreX Avatar answered Dec 21 '22 23:12

TiGreX