How to set an HttpCalloutMock to reply differently on subsequent requests to the same endpoint?

This test works just fine for me:

@IsTest
class Demo
{
    class Mock implements HttpCalloutMock
    {
        Boolean hasResponded = false;
        public HttpResponse respond(HttpRequest request)
        {
            HttpResponse response = new HttpResponse();
            response.setStatusCode(hasResponded ? 204 : 200);
            hasResponded = true;
            return response;
        }
    }
    static testmethod void testMyMock()
    {
        HttpRequest request = new HttpRequest();
        request.setEndpoint('...');
        request.setMethod('GET');

        Test.startTest();
            Test.setMock(HttpCalloutMock.class, new Mock());
            HttpResponse response1 = new Http().send(request);
            HttpResponse response2 = new Http().send(request);
        Test.stopTest();

        system.assertEquals(200, response1.getStatusCode());
        system.assertEquals(204, response2.getStatusCode());
    }
}

The same test passes if you change the mock definition to:

class Mock implements HttpCalloutMock
{
    Integer timesCalled = 0;
    public HttpResponse respond(HttpRequest request)
    {
        HttpResponse response = new HttpResponse();
        response.setStatusCode(timesCalled++ > 0 ? 204 : 200);
        return response;
    }
}

IMHO This is the way to go. Control what is returned from the test method itself by constructing the response on the fly. No need for multiple or complex mock classes with this

Since question is not a duplicate and the answer is, just copying the answer from sfdcfox

Help on Invokable Apex Test class and @Future callout Apex test Class

Basically, you need to know about how to test HTTP callouts, and how to test future methods.

Once you've gotten that far, you'll see that the unit test would look like:

@isTest class MakeCalloutTest {
    // Simple echo callout class
    // Returns whatever response we tell it to when asked
    class EchoHttpMock implements HttpCalloutMock {
        HttpResponse res;
        EchoMock(HttpResponse r) {
            res = r;
        }
        // This is the HttpCalloutMock interface method
        public HttpResponse respond(HttpRequest req) {
            return res;
        }
    }

    @isTest static void test() {
        // Avoid using live data
        List<Lead> leads = new List<Lead>{ new Lead(LastName='Test',Company='test') };
        insert leads;
        // We tell it what to simulate
        HttpResponse res = new HttpResponse();
        res.setBody('<?xml version="1.0" encoding="utf-8"?><root U_Id="12345"></root>');
        res.setStatusCode(200);
        // This allows the callout to succeed
        Test.setMock(HttpCalloutMock.class, new EchoHttpMock(res));
        // Start the test
        Test.startTest();
        // Enqueue the future call
        MakeCallout.invokeleadcallout(leads);
        // Trigger future method
        Test.stopTest();
        // Verify logic
        leads = [select id__c from lead];
        System.assertEquals('12345', leads[0].Id__c);
    }
}

Note: This doesn't cover the "catch" part of your try-catch block. Once you've gotten as far as covering most of your code, the catch block should be pretty simple (hint: you can construct and throw CalloutException manually from a HttpCalloutMock).

Credit to sfdcfox