The compilation problem is that the definition of u
is local to one method and you are trying to reference it in a another method. You can get a local reference to that user to avoid the compilation error like this:
static testMethod void testOppsPt1(){
User u = [select Id from User where Username = 'astest@wexeurope.com'];
List<Opportunity> immOpportunitys = new List<Opportunity>();
for (Integer i = 0; i < 1; i++) {
...
}
This keeps all the data creation in the @TestSetup method that is run once only irrespective of how many test methods there are.
PS
Note that by design all static variables are cleared before each test method is executed; querying isthe recommended approach.
To use stub API, we cannot have inline SOQL, so change DistributedMSelector as below:
public class DistributedMSelector {
public static UserSelector userSelectorObj;
public static Map<string, user> getUserMap(Set<String> employeeIdSet){
Map<String, User> employeeData = new Map<String, User> ();
for(user u: userSelectorObj.queryUsers(employeeIdSet)){
employeeData.put(u.employeeNumber, u);
}
return employeeData;
}
}
Create a new class named UserSelector as below:
public class UserSelector {
public List<User> queryUsers(Set<String> employeeIdSet){
return [SELECT id, employeeNumber, firstName, lastName, email FROM User WHERE employeeNumber in:employeeIdSet ];
}
}
Update MockProvider class as below:
@isTest
public class MockProvider implements System.StubProvider {
public static List<User> userList;
public Object handleMethodCall(Object stubbedObject, String stubbedMethodName,
Type returnType, List<Type> listOfParamTypes, List<String> listOfParamNames,
List<Object> listOfArgs) {
if (stubbedMethodName == 'queryUsers'){
return userList;
}
}
}
And finally change your test class as below:
private class DistributedMSelector_Test {
@IsTest
static void testGetUserMap() {
String userListJSON = '[{"attributes":{"type":"User"},"Id":"005M0000007s8M2IAI", "EmployeeNumber": "abc"}]';
MockProvider.userList = (List<User>)JSON.deserialize(quotesListJSON, List<User>.class);
DistributedMSelector.userSelectorObj = (UserSelector)MockUtil.createMock(UserSelector.class);
Map<String, User> userMap = DistributedMSelector.getUserMap(new Set<String>{'abc'});
System.assertEquals(1, userMap.keySet().size());
}
}
Here is how it works:
- To use stub API, don't do inline SOQL but instead use a selector and inject that selector to the actual class.
- Update MockProvider to return what you want when it is invoked in the context of test class. Check the if condition inside
MockProvider.handleMethodCall
. You can enhance it further.
- Test class should create mock selector object and inject this object to the actual class. Also, set what you want the MockProvider to return when it is invoked.
Best Answer
The Test Setup method runs once and only once for the given test class (at least when running all tests; I'm not sure what happens if you run tests selectively, by method name).
When a test class is to be executed, if there's a setup method this is called once, always before any of the test methods are invoked (with these later running sequentially or in parallel, based on your settings). At the end of the setup execution the unit testing infrastructure effectively sets a database "save point". Each individual test is then run with the database set to that "save point". After all (relevant) tests are run, the database is reset to the state it was before running the setup method.
Note that each test is run in an isolated transaction on top of the "save point". It is for this reason that static variables set in the setup method are not retained.
This has several advantages:
The only real disadvantage is complexity in retrieving the IDs and data which necessarily happens in one or more other methods outside the setup (you could vote for this idea, btw). We address this by having specific method(s), that we organize in the code to be next to the test setup method, that "get" the required record(s).