11

I have a base class called "Question" and several child classes such as "TrueFalse", "MultipleChoice", "MatchPairs" etc...

The base class has methods with logic that all of the child classes use, such as sending off scores and raising events.

I have set my unit tests up for the child classes but I am not sure how I can setup unit tests for the methods in the base class.

I did some searching and I understand I need to create a Mock of the class but I am not sure how to do this as I have only seen how to do this on an instantiable object.

I have Moq & NUnit installed in project so ideally id like to use this. I am still new to programming and this is my first time adding unit tests so I appreciate any advice you can give me.

I did a search on site first and found a couple of similar questions but they did not give any example on how to do it, just that it needed to be mocked.

Many thanks.

Adam Rackis
  • 82,527
  • 56
  • 270
  • 393
Guerrilla
  • 13,375
  • 31
  • 109
  • 210
  • Have a test-dummy class that extends it...? – cHao Dec 15 '13 at 04:30
  • So you basically need to know how to mock an abstract class. That's it - google for that and you should find what you need (I'd help you, but I've never used moq) – Adam Rackis Dec 15 '13 at 04:37
  • @cHao Yeah that makes sense. So I just create a dummy child class and pass all directly to base. Its obvious when you think about it, its the other articles that confused me, it seemed that people were recommending to use Moq framework to instantiate an instance of abstract base class and I could not find out how to do this. I will create a dumy class in my test project without using Moq at all. – Guerrilla Dec 15 '13 at 04:38
  • @AdamRackis yes I did google it and found people talking about it but no code sample – Guerrilla Dec 15 '13 at 04:39
  • NO - use moq to create a mock of your abstract base class. That's it. That's what mocking frameworks are for – Adam Rackis Dec 15 '13 at 04:39

3 Answers3

14

From this answer it looks like what you need is something along these lines:

[Test]
public void MoqTest()
{
    var mock = new Moq.Mock<AbstractBaseClass>();            
    // set the behavior of mocked methods
    mock.Setup(abs => abs.Foo()).Returns(5);

    // getting an instance of the class
    var abstractBaseClass = mock.Object;
    // Asseting it actually works :)
    Assert.AreEqual(5, abstractBaseClass.Foo());
}
Community
  • 1
  • 1
Adam Rackis
  • 82,527
  • 56
  • 270
  • 393
  • Thank you Adam. This is what I needed, I dont know why I couldnt find this when I searched, thankyou. – Guerrilla Dec 15 '13 at 04:45
  • 1
    I cannot get this working. I get error "Method is not public". I used `var mock = new Mock(new object[]{"question text",true}); var Question = mock.Object; Question.Ask(); mock.Verify(m => m.Ask());` Method is public but I think issue is that class is abstract. – Guerrilla Dec 15 '13 at 05:52
  • @guerr - I don't think that's how you set up your mock. I would create it the same way the code does, and then set up your mocked values with Setup, or whatever other means moq gives you – Adam Rackis Dec 15 '13 at 06:19
  • If I use setup to define what the method returns then am I testing the logic inside the method? Isnt that for when im testing a class that uses another class and I want to fake the behaviour it returns? Sorry for the noob questions, I have done a lot of reading but this is my first time actually tackling this. I really appreciate the help – Guerrilla Dec 15 '13 at 06:31
  • I made a new question with the code i used and message I got so it is clearer - http://stackoverflow.com/questions/20591869/using-moq-to-test-an-abstract-class – Guerrilla Dec 15 '13 at 06:43
  • Your new question is worded well, I upvoted it. Hopefully you'll get a good answer. – Adam Rackis Dec 15 '13 at 06:45
  • How can this work when the abstract class does not have a zero parameter argument constructor? – devyJava Apr 18 '22 at 03:34
0

I was trying to mock an abstract class and this way didn't worked for me. what did work was to create a new class that extended the abstract class

class newclass : abstractClass
{
}

like this I could set the property and test the main method

msenos
  • 39
  • 1
  • 11
0

There is no simple way to test it,

The best option is:

  • mark base class methods as virtual
  • create test classes for each of the "TrueFalse", "MultipleChoice", "MatchPairs" classes with virtual methods overridden and invoke public Abstract method.

So for example you have next inheritance structure

class Question {
     protected virtual bool CheckCorrect(params int[] answers){
          return answers.Any(x => x== 42);
     }
}

class TrueFalse: Question {
     
     public int SelectedAnswer {get;set;}
     public bool IsCorrect(){
          return CheckCorrect(SelectedAnswer );
     }
}
class MultipleChoice: Question {
     public int[] SelectedAnswers {get;set;}
     public bool IsCorrect(){
          return CheckCorrect(SelectedAnswers );
     }
}

Test methods for this:

abstract class TrueFalseTest: TrueFalseTest{

     public abstract bool CheckCorrectReal(params int[] answers);
     
     public override bool CheckCorrect(params int[] answers){
          return CheckCorrect(SelectedAnswer );
     }
}

abstract  class MultipleChoiceTest: MultipleChoice {
     public abstract bool CheckCorrectReal(params int[] answers);
     
     public override bool CheckCorrect(params int[] answers){
          return CheckCorrect(SelectedAnswer );
     }
}

And test methods itself:

class TestQuestionForms{
    [Fact]
    public void TrueFalseTest_ShouldExecute_CheckCorrectReal()
    {
        //setup
        var mock = new Mock<TrueFalseTest>();

        mock.Setup(q => q.CheckCorrectReal(It.IsAny<int[] answers>))
            .Returns(true);

        //action
        mock.Object.IsCorrect();
       
       //assert
       mock.Verify(db => db.CheckCorrectReal());

    }
    [Fact]
    public void MultipleChoiceTest_ShouldExecute_CheckCorrectReal()
    {   
        //setup
        var mock = new Mock<MultipleChoiceTest>();

        mock.Setup(q => q.CheckCorrectReal(It.IsAny<int[] answers>))
            .Returns(true);

        //action
        mock.Object.IsCorrect();
       
       //assert
       mock.Verify(db => db.CheckCorrectReal());

    }
}
Stadub Dima
  • 858
  • 10
  • 24
  • What is the purpose of overriding `CheckCorrect` in MultipleChoiceTest abstract class when it isn't being executed in your test. Am I missing something here? – devyJava Apr 18 '22 at 03:32