Does addError() work outside of triggers?

It only works on trigger context records, but it can be applied to those records outside of a trigger. You cannot call this method on a record which is not yet in a trigger context, then have the error carry through to the trigger context.

This code won't prevent DML:

Account record = new Account();
record.addError('You cannot insert this record');
insert record;

However, this code will:

trigger Account on Account (before insert)
{
    PreventDml.validate(trigger.new);
}
public with sharing class PreventDml
{
    public void validate(List<SObject> records)
    {
        for (SObject record : records)
        {
            record.addError('You cannot insert this record');
        }
    }
}

If you are trying to test this code, the only realistic, effective way to make sure it does what you want is to run the trigger. For example, in this scenario I might have a test like:

@IsTest
class AccountTriggerTests
{
    @IsTest static void testPreventDml()
    {
        DmlException expectedException;
        Test.startTest();
            try
            {
                insert new Account();
            }
            catch (DmlException dmx)
            {
                expectedException = dmx;
            }
        Test.stopTest();

        system.assertNotEquals(null, expectedException,
            'You should not be able to insert any Account');
        system.assertEquals(0, [SELECT count() FROM Account],
            'The database should be unchanged');
    }
}

addError won't block future DML operations, only those already in progress. You can use addError in any class, but it won't have any effect on future operations. As an example of what would work:

trigger myFieldBlock on Opportunity {
  myFieldBlock.validate(Trigger.new);
}

public class myFieldBlock {
  public static void validate(Opportunity[] records) {
    records[0].My_Field__c.addError('Some error');
  }
}

You can also use addError to display errors on a Visualforce page:

public class VFController {
  public Account record { get; set; }
  public VFController() {
    record = new Account();
  }
  public void showError() {
    record.Name.addError('Some error');
  }
}

<apex:page controller="VFController">
  <apex:form>
    <apex:inputField value="{!record.Name}" />
    <apex:commandButton value="Show Error" action="{!showError}" />
  </apex:form>
</apex:page>