Home > Software design >  Unit testing C# with protected methods and Mocking fields
Unit testing C# with protected methods and Mocking fields

Time:07-08

Below is code from a NuGet package which is used by our main project, MyClass is called via the main project with authentication. The method GetMyAppStoreConfig() will only work when calling from the main project via authentication.

  public class MyClass : MyClassBase
    {
        private SomeClass1 someClass1;
        private MyAppStore myAppStore; // Field newly added
        
        public MyClass(params object[] args)
            : base(args)
        {
            this.someClass1 = new SomeClass1();
            this.myAppStore = new MyAppStore(GetMyAppStoreConfig()); // Field newly added
        }

           protected override async Task<SomeValues> Process(
            SomeClass2 someClass2,
            SomeClass3 someClass3,
            SomeClass4 someClass4
           )
        {
          ...
          ...
          ...
  
        }
     
    // Below method uses myAppStore
    // Method newly added
        protected override async Task<SomeValues> ProcessWithAuth(
            SomeClass5 someClass5
           )
        {
          ...
          ...
          ...
  
        }

        private AppStoreConfig GetMyAppStoreConfig(){
        ...
        ...
        }


    }

Earlier the test code for above was.

 [TestClass()]
    public class MyClassTests : MyClass 
    {
        

        [TestMethod()]
        public void test1()
        {   
            ...
            ... = this.Process(someClass2,someClass3,someClass4);
            ...
        }
   }

But now it doesn't work as it throws error in GetMyAppStoreConfig(). Currently I don't need to test ProcessWithAuth(), what changes I should make for the test case to work.

I currently cannot create one more constructor and cannot change the protection level in MyClass.cs .

Process() has some code which I want to run in tests and not simply mock.

CodePudding user response:

Below code worked for me. Needed to make getData virtual and create a no argument constructor in MyAppStore.

    [TestClass()]
    public class MyClassTests 
    {
        private MyClass _myClass;
        private PrivateObject privateObject;

        [TestInitialize()]
        public void init()
        {
            this._myClass = (MyClass)FormatterServices.GetSafeUninitializedObject(typeof(MyClass));
            privateObject = new PrivateObject(this._myClass);
            privateObject.SetField("someClass1;", new SomeClass1());

            var myAppStore  = SetUpMyAppStore();
            
            privateObject.SetField("myAppStore", myAppStore);
        }

        private SetUpMyAppStore()
        {
              var myAppStore = new Mock<MyAppStore>();

              var myData = new MyData();
              myData.val = "1123"
              myAppStore.Setup(x => x.getData("data1")).Returns(Task.FromResult(myData));

              myData = new MyData();
              myData.val = "1124"
              myAppStore.Setup(x => x.getData("data2")).Returns(Task.FromResult(myData));

              return myAppStore.Object;

        }


        

        [TestMethod()]
        public void test1()
        {
            ...
            ... =  (Task<SomeValues>)this.privateObject.Invoke("Process",someClass2,someClass3,someClass4);
            ...
           
        } 


        [TestMethod()]
        public void test2()
        {
            ...
            ... =  (Task<SomeValues>)this.privateObject.Invoke("ProcessWithAuth",someClass5);
            ...
           
        } 
         
    }     ```
  • Related