简体   繁体   中英

How to test multiple objects of the same type in NUnit

I am currently trying to learn NUnit for the 1st time.

For a C# program I want to develop using TDD, I have decided I want to write a User class to start with. This User class will (semantically) look like this:

using System;

namespace SSH_file_drop
{
    public class User
    {
        private Boolean authenticated = false;

        public string userName = null;

        //one-time object 'transmission' instance to allow single-use file transmission field
        Transmission fileVehicle = null;

        //property to discern whether user has been correctly authenticated
        public Boolean isAuthenticated 
        {
            get;
        }

        public Boolean canSend ()
        {
            if (authenticated)
            {
                return this.userType != "sender";
            }
            return false;
        }

        public User(String inputUName)
        {
            String userName = inputUName;
        }

        public static void generateUser(string userName)
        {
            //contact server to attempt to register new user
        }

        public void ChangePassword(String oldPassword, String newPassword)
        {
            //ask server to change user password
        }

        public Boolean SetUpTransmission()
        {
            if (canSend())
            {
                try
                {
                    fileVehicle = new Transmission(this);
                    return true;
                }
                catch (e)
                {
                    //write exception message
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
    }
}

Really just placeholder code at the moment.

In order to test the User class however I am trying to write a TestFixture that creates separate instances of the User class, and somehow stores them persistently until teardown, enacting the same tests upon each object.

My idea was to create an array of User objects as a TestCase data source to test everything in order via the [Order(<n>)] attribute (bar User instance initialisation test method), but I have read here that a new instance of the TestFixture will be created for each method within it at runtime, so I would not be able to modify persistent data in a Test Fixture in this way.

Since I am trying to implement stateful logic - User object isAuthenticated() (and this authentication is dependent for subsequent tests after this as all User data is modelled as being stored in a remote database), is there a way to proceed without creating tests with repeated operations (create object, authenticate,check userType etc.), and thus multiple assertions?

Answering the part of your question that deals with how NUnit works...

The answer you quoted, regarding the lifetime of fixture instances in NUnit is misleading and a little surprising because there is no big mystery about it!

The quotation from Jim Newkirk, the primary develope of NUnit V2, is just a statement of how he wished he had done NUnit V2. He carried out those ideas in the xUnit.net framework, but it isn't relevant to NUnit 3.

NUnit 3, like NUnit V2,creates a single instance of a TestFixture , which is used for all your tests. You can create objects to use in your tests using [OneTimeSetUp] and store them as members of the class.If those objects are stateful, you should avoid use of parallel test execution for the tests in the fixture that make use of them.

If additional per-test setup is needed, then you can use [SetUp] for that purpose and [TearDown] to remove any changes that would affect subsequent tests negatively.

You can also specify ordering of tests, but this is usually not a very good idea because one broken test may cause subsequent tests to also break. Try to make each test independent if you can.

Note also that if you want to be able to run the same fixture multiple times against various types of objects, a parameterized fixture is a good option. Just pass into the constructor enough information so that the proper object initialization can be done in the one-time setup.

Be sure to read the details of all the above in the docs: https://github.com/nunit/docs/wiki

The approach that we take in this situation is to create helper methods that manufacture instances of the class under test with the appropriate state.

This is effectively the approach that you have mentioned except with a slightly different approach.

The other issues to consider with your proposed approach, which the approach I suggest would avoid, is ordered and/or parallel execution of tests: if you have a series of stateful objects, the tests will not be able to be reliably run in parallel or out of order.

Note that in order to fully support this mode of test development, you may need to introduce test-only methods and.or constructors.

For example, IsAuthenticated in your class is a readonly property. In order to simulate this property being on or off, you may need to introduce a test-only constructor (which I tend to avoid since someone will use it at some point even though you have documented that it is for test only) or change the implementation of the property and add a setter method.

If you change the Authenticated property to use a backing store member, then you can add a test-only method (although there is a chance that another developer will use this method, if it is well-named, it becomes much more obvious when it is used than a constructor).

private bool m_IsAuthenticated;

public bool IsAuthenticated {
  get {
    return m_IsAuthenticated;
  }
}

public void Set_IsAuthenticated_ForTestONLY(bool value) {
  m_IsAuthenticated = value;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM